123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392 |
- /* quic.c
- *
- * Copyright (C) 2006-2024 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
- */
- /* Name change compatibility layer no longer needs to be included here */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #include <wolfssl/wolfcrypt/settings.h>
- #ifdef NO_INLINE
- #include <wolfssl/wolfcrypt/misc.h>
- #else
- #define WOLFSSL_MISC_INCLUDED
- #include <wolfcrypt/src/misc.c>
- #endif
- #ifndef WOLFCRYPT_ONLY
- #ifdef WOLFSSL_QUIC
- #include <wolfssl/error-ssl.h>
- #include <wolfssl/ssl.h>
- #include <wolfssl/internal.h>
- #include <wolfssl/openssl/buffer.h>
- #include <wolfssl/openssl/ecdsa.h>
- #include <wolfssl/openssl/evp.h>
- #include <wolfssl/openssl/kdf.h>
- static int qr_length(const uint8_t *data, size_t len)
- {
- word32 rlen;
- if (len < 4) {
- return 0;
- }
- c24to32(&data[1], &rlen);
- return (int)rlen + 4;
- }
- static void quic_record_free(WOLFSSL *ssl, QuicRecord *r)
- {
- (void)ssl;
- if (r->data) {
- ForceZero(r->data, r->capacity);
- XFREE(r->data, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
- }
- XFREE(r, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
- }
- static QuicRecord *quic_record_make(WOLFSSL *ssl,
- WOLFSSL_ENCRYPTION_LEVEL level,
- const uint8_t *data, size_t len)
- {
- QuicRecord *qr;
- qr = (QuicRecord*)XMALLOC(sizeof(*qr), ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
- if (qr) {
- memset(qr, 0, sizeof(*qr));
- qr->level = level;
- if (level == wolfssl_encryption_early_data) {
- qr->capacity = qr->len = (word32)len;
- }
- else {
- qr->capacity = qr->len = (word32) qr_length(data, len);
- if (qr->capacity > WOLFSSL_QUIC_MAX_RECORD_CAPACITY) {
- WOLFSSL_MSG("QUIC length read larger than expected");
- quic_record_free(ssl, qr);
- return NULL;
- }
- }
- if (qr->capacity == 0) {
- qr->capacity = 2*1024;
- }
- qr->data = (uint8_t*)XMALLOC(qr->capacity, ssl->heap,
- DYNAMIC_TYPE_TMP_BUFFER);
- if (!qr->data) {
- quic_record_free(ssl, qr);
- return NULL;
- }
- }
- return qr;
- }
- static int quic_record_complete(QuicRecord *r)
- {
- return r->len && r->end >= r->len;
- }
- static int quic_record_done(QuicRecord *r)
- {
- return r->len && r->end >= r->len && r->start >= r->end;
- }
- static int quic_record_append(WOLFSSL *ssl, QuicRecord *qr, const uint8_t *data,
- size_t len, size_t *pconsumed)
- {
- size_t missing, consumed = 0;
- int ret = WOLFSSL_SUCCESS;
- (void)ssl;
- if (!qr->len && len) {
- missing = 4 - qr->end;
- if (len < missing) {
- XMEMCPY(qr->data + qr->end, data, len);
- qr->end += (word32)len;
- consumed = len;
- goto cleanup; /* len consumed, but qr->len still unknown */
- }
- XMEMCPY(qr->data + qr->end, data, missing);
- qr->end += (word32)missing;
- len -= missing;
- data += missing;
- consumed = missing;
- qr->len = (word32)qr_length(qr->data, qr->end);
- /* sanity check on length read from wire before use */
- if (qr->len > WOLFSSL_QUIC_MAX_RECORD_CAPACITY) {
- WOLFSSL_MSG("Length read for quic is larger than expected");
- ret = BUFFER_E;
- goto cleanup;
- }
- if (qr->len > qr->capacity) {
- uint8_t *ndata = (uint8_t*)XREALLOC(qr->data, qr->len, ssl->heap,
- DYNAMIC_TYPE_TMP_BUFFER);
- if (!ndata) {
- ret = WOLFSSL_FAILURE;
- goto cleanup;
- }
- qr->data = ndata;
- qr->capacity = qr->len;
- }
- }
- if (quic_record_complete(qr) || len == 0) {
- return 0;
- }
- missing = qr->len - qr->end;
- if (len > missing) {
- len = missing;
- }
- XMEMCPY(qr->data + qr->end, data, len);
- qr->end += (word32)len;
- consumed += len;
- cleanup:
- *pconsumed = (ret == WOLFSSL_SUCCESS) ? consumed : 0;
- return ret;
- }
- static word32 add_rec_header(byte* output, word32 length, byte type)
- {
- RecordLayerHeader* rl;
- /* record layer header */
- rl = (RecordLayerHeader*)output;
- if (rl == NULL) {
- return 0;
- }
- rl->type = type;
- rl->pvMajor = SSLv3_MAJOR;
- rl->pvMinor = TLSv1_2_MINOR;
- c16toa((word16)length, rl->length);
- return RECORD_HEADER_SZ;
- }
- static sword32 quic_record_transfer(QuicRecord* qr, byte* buf, word32 sz)
- {
- word32 len = qr->end - qr->start;
- word32 offset = 0;
- word32 rlen;
- if (len <= 0) {
- return 0;
- }
- /* We check if the buf is at least RECORD_HEADER_SZ */
- if (sz < RECORD_HEADER_SZ) {
- return WOLFSSL_FATAL_ERROR;
- }
- if (qr->rec_hdr_remain == 0) {
- /* start a new TLS record */
- rlen = (qr->len <= (word32)MAX_RECORD_SIZE) ?
- qr->len : (word32)MAX_RECORD_SIZE;
- offset += add_rec_header(buf, rlen,
- (qr->level == wolfssl_encryption_early_data) ?
- application_data : handshake);
- qr->rec_hdr_remain = rlen;
- sz -= offset;
- }
- if (len > qr->rec_hdr_remain) {
- len = qr->rec_hdr_remain;
- }
- if (len > sz) {
- len = sz;
- }
- if (len > 0) {
- XMEMCPY(buf + offset, qr->data + qr->start, len);
- qr->start += len;
- qr->rec_hdr_remain -= len;
- }
- return (sword32)(len + offset);
- }
- const QuicTransportParam* QuicTransportParam_new(const uint8_t* data,
- size_t len, void* heap)
- {
- QuicTransportParam* tp;
- if (len > 65353) return NULL;
- tp = (QuicTransportParam*)XMALLOC(sizeof(*tp), heap, DYNAMIC_TYPE_TLSX);
- if (!tp) return NULL;
- tp->data = (uint8_t*)XMALLOC(len, heap, DYNAMIC_TYPE_TLSX);
- if (!tp->data) {
- XFREE(tp, heap, DYNAMIC_TYPE_TLSX);
- return NULL;
- }
- XMEMCPY((uint8_t*)tp->data, data, len);
- tp->len = (word16)len;
- return tp;
- }
- const QuicTransportParam* QuicTransportParam_dup(const QuicTransportParam* tp,
- void* heap)
- {
- QuicTransportParam* tp2;
- tp2 = (QuicTransportParam*)XMALLOC(sizeof(*tp2), heap, DYNAMIC_TYPE_TLSX);
- if (!tp2) return NULL;
- tp2->data = (uint8_t*)XMALLOC(tp->len, heap, DYNAMIC_TYPE_TLSX);
- if (!tp2->data) {
- XFREE(tp2, heap, DYNAMIC_TYPE_TLSX);
- return NULL;
- }
- XMEMCPY((uint8_t*)tp2->data, tp->data, tp->len);
- tp2->len = tp->len;
- return tp2;
- }
- void QuicTransportParam_free(const QuicTransportParam* tp, void* heap)
- {
- (void)heap;
- if (tp) {
- if (tp->data) XFREE((uint8_t*)tp->data, heap, DYNAMIC_TYPE_TLSX);
- XFREE((void*)tp, heap, DYNAMIC_TYPE_TLSX);
- }
- }
- void wolfSSL_quic_clear(WOLFSSL* ssl)
- {
- QuicEncData* qd;
- /* keep
- * - ssl->quic.transport_local
- * - ssl->quic.method
- * - ssl->quic.transport_version
- * reset/free everything else
- */
- if (ssl->quic.transport_peer) {
- QTP_FREE(ssl->quic.transport_peer, ssl->heap);
- ssl->quic.transport_peer = NULL;
- }
- if (ssl->quic.transport_peer_draft) {
- QTP_FREE(ssl->quic.transport_peer_draft, ssl->heap);
- ssl->quic.transport_peer_draft = NULL;
- }
- ssl->quic.enc_level_write = wolfssl_encryption_initial;
- ssl->quic.enc_level_latest_recvd = wolfssl_encryption_initial;
- while ((qd = ssl->quic.input_head)) {
- ssl->quic.input_head = qd->next;
- quic_record_free(ssl, qd);
- }
- ssl->quic.input_tail = NULL;
- ssl->quic.output_rec_remain = 0;
- if (ssl->quic.scratch) {
- quic_record_free(ssl, ssl->quic.scratch);
- ssl->quic.scratch = NULL;
- }
- }
- void wolfSSL_quic_free(WOLFSSL* ssl)
- {
- wolfSSL_quic_clear(ssl);
- if (ssl->quic.transport_local) {
- QTP_FREE(ssl->quic.transport_local, ssl->heap);
- ssl->quic.transport_local = NULL;
- }
- ssl->quic.method = NULL;
- }
- static int ctx_check_quic_compat(const WOLFSSL_CTX* ctx)
- {
- WOLFSSL_ENTER("ctx_check_quic_compat");
- if (ctx->method->version.major != SSLv3_MAJOR
- || ctx->method->version.minor != TLSv1_3_MINOR
- || (ctx->method->downgrade && ctx->minDowngrade < TLSv1_3_MINOR)) {
- WOLFSSL_MSG_EX("ctx not quic compatible: vmajor=%d, vminor=%d, downgrade=%d",
- ctx->method->version.major,
- ctx->method->version.minor,
- ctx->method->downgrade
- );
- return WOLFSSL_FAILURE;
- }
- return WOLFSSL_SUCCESS;
- }
- static int check_method_sanity(const WOLFSSL_QUIC_METHOD* m)
- {
- WOLFSSL_ENTER("check_method_sanity");
- if (m && m->set_encryption_secrets
- && m->add_handshake_data
- && m->flush_flight
- && m->send_alert) {
- return WOLFSSL_SUCCESS;
- }
- return WOLFSSL_FAILURE;
- }
- int wolfSSL_CTX_set_quic_method(WOLFSSL_CTX* ctx,
- const WOLFSSL_QUIC_METHOD* quic_method)
- {
- WOLFSSL_ENTER("wolfSSL_CTX_set_quic_method");
- if (ctx_check_quic_compat(ctx) != WOLFSSL_SUCCESS
- || check_method_sanity(quic_method) != WOLFSSL_SUCCESS) {
- return WOLFSSL_FAILURE;
- }
- ctx->quic.method = quic_method;
- return WOLFSSL_SUCCESS;
- }
- int wolfSSL_set_quic_method(WOLFSSL* ssl,
- const WOLFSSL_QUIC_METHOD* quic_method)
- {
- WOLFSSL_ENTER("wolfSSL_set_quic_method");
- if (ctx_check_quic_compat(ssl->ctx) != WOLFSSL_SUCCESS
- || check_method_sanity(quic_method) != WOLFSSL_SUCCESS) {
- return WOLFSSL_FAILURE;
- }
- ssl->quic.method = quic_method;
- return WOLFSSL_SUCCESS;
- }
- int wolfSSL_is_quic(WOLFSSL* ssl)
- {
- return WOLFSSL_IS_QUIC(ssl);
- }
- WOLFSSL_ENCRYPTION_LEVEL wolfSSL_quic_read_level(const WOLFSSL* ssl)
- {
- return ssl->quic.enc_level_read;
- }
- WOLFSSL_ENCRYPTION_LEVEL wolfSSL_quic_write_level(const WOLFSSL* ssl)
- {
- return ssl->quic.enc_level_write;
- }
- int wolfSSL_set_quic_transport_params(WOLFSSL* ssl,
- const uint8_t* params,
- size_t params_len)
- {
- const QuicTransportParam* tp;
- int ret = WOLFSSL_SUCCESS;
- WOLFSSL_ENTER("wolfSSL_set_quic_transport_params");
- if (!params || params_len == 0) {
- tp = NULL;
- }
- else {
- tp = QuicTransportParam_new(params, params_len, ssl->heap);
- if (!tp) {
- ret = WOLFSSL_FAILURE;
- goto cleanup;
- }
- }
- if (ssl->quic.transport_local)
- QTP_FREE(ssl->quic.transport_local, ssl->heap);
- ssl->quic.transport_local = tp;
- cleanup:
- WOLFSSL_LEAVE("wolfSSL_set_quic_transport_params", ret);
- return ret;
- }
- void wolfSSL_get_peer_quic_transport_params(const WOLFSSL* ssl,
- const uint8_t** out_params,
- size_t* out_params_len)
- {
- const QuicTransportParam* tp = ssl->quic.transport_peer ?
- ssl->quic.transport_peer : ssl->quic.transport_peer_draft;
- *out_params = tp ? tp->data : NULL;
- *out_params_len = tp ? tp->len : 0;
- }
- int wolfSSL_get_peer_quic_transport_version(const WOLFSSL* ssl)
- {
- return ssl->quic.transport_peer ?
- TLSX_KEY_QUIC_TP_PARAMS : (ssl->quic.transport_peer_draft ?
- TLSX_KEY_QUIC_TP_PARAMS : -1);
- }
- void wolfSSL_set_quic_use_legacy_codepoint(WOLFSSL* ssl, int use_legacy)
- {
- ssl->quic.transport_version = use_legacy ? TLSX_KEY_QUIC_TP_PARAMS_DRAFT
- : TLSX_KEY_QUIC_TP_PARAMS;
- }
- void wolfSSL_set_quic_transport_version(WOLFSSL* ssl, int version)
- {
- if (version == TLSX_KEY_QUIC_TP_PARAMS
- || version == TLSX_KEY_QUIC_TP_PARAMS_DRAFT
- || !version) {
- ssl->quic.transport_version = version;
- }
- else {
- WOLFSSL_MSG("wolfSSL_set_quic_transport_version: invalid version");
- }
- }
- int wolfSSL_get_quic_transport_version(const WOLFSSL* ssl)
- {
- return ssl->quic.transport_version;
- }
- int wolfSSL_quic_add_transport_extensions(WOLFSSL* ssl, int msg_type)
- {
- /* RFC 9001, ch. 8.2: "The quic_transport_parameters extension is carried
- * in the ClientHello and the EncryptedExtensions messages during the
- * handshake. Endpoints MUST send the quic_transport_parameters extension;"
- * Which means, at least one. There can be more to signal compatibility to
- * older/newer versions.
- */
- int ret = 0, is_resp = (msg_type == encrypted_extensions);
- if (ssl->quic.transport_local == NULL) {
- return QUIC_TP_MISSING_E;
- }
- if (is_resp) {
- /* server response: time to decide which version to use */
- if (ssl->quic.transport_peer && ssl->quic.transport_peer_draft) {
- if (ssl->quic.transport_version == TLSX_KEY_QUIC_TP_PARAMS_DRAFT) {
- ret = TLSX_QuicTP_Use(ssl,
- TLSX_KEY_QUIC_TP_PARAMS_DRAFT, is_resp);
- QTP_FREE(ssl->quic.transport_peer, ssl->heap);
- ssl->quic.transport_peer = NULL;
- }
- else {
- ret = TLSX_QuicTP_Use(ssl, TLSX_KEY_QUIC_TP_PARAMS, is_resp);
- QTP_FREE(ssl->quic.transport_peer_draft,
- ssl->heap);
- ssl->quic.transport_peer_draft = NULL;
- }
- }
- else {
- if (ssl->quic.transport_version == TLSX_KEY_QUIC_TP_PARAMS_DRAFT
- && ssl->quic.transport_peer_draft) {
- ret = TLSX_QuicTP_Use(ssl, TLSX_KEY_QUIC_TP_PARAMS_DRAFT,
- is_resp);
- }
- else if (ssl->quic.transport_peer) {
- ret = TLSX_QuicTP_Use(ssl, TLSX_KEY_QUIC_TP_PARAMS, is_resp);
- }
- else {
- /* no match, send none, will let the client fail */
- }
- }
- }
- else {
- /* client hello */
- if (ssl->quic.transport_version == 0) {
- /* not being set to a particular id, we send both draft+v1 */
- ret = TLSX_QuicTP_Use(ssl, TLSX_KEY_QUIC_TP_PARAMS, is_resp)
- || TLSX_QuicTP_Use(ssl, TLSX_KEY_QUIC_TP_PARAMS_DRAFT, is_resp);
- }
- else {
- /* otherwise, send the version configured */
- ret = TLSX_QuicTP_Use(ssl, (TLSX_Type)ssl->quic.transport_version,
- is_resp);
- }
- }
- return ret;
- }
- #define QUIC_HS_FLIGHT_LIMIT_DEFAULT (16* 1024)
- size_t wolfSSL_quic_max_handshake_flight_len(const WOLFSSL* ssl,
- WOLFSSL_ENCRYPTION_LEVEL level)
- {
- switch (level) {
- case wolfssl_encryption_initial:
- case wolfssl_encryption_application:
- return QUIC_HS_FLIGHT_LIMIT_DEFAULT;
- case wolfssl_encryption_early_data:
- return 0; /* QUIC does not send at this level */
- case wolfssl_encryption_handshake:
- /* during handshake itself, certificates may be exchanged which
- * exceed our default limit, advise a higher limit one.
- */
- if (ssl->options.side == WOLFSSL_SERVER_END) {
- if (ssl->options.verifyPeer
- && MAX_CERTIFICATE_SZ > QUIC_HS_FLIGHT_LIMIT_DEFAULT)
- return MAX_CERTIFICATE_SZ;
- }
- else {
- /* clients may receive the server cert chain
- */
- if (2*MAX_CERTIFICATE_SZ > QUIC_HS_FLIGHT_LIMIT_DEFAULT)
- return 2*MAX_CERTIFICATE_SZ;
- }
- return QUIC_HS_FLIGHT_LIMIT_DEFAULT;
- }
- return 0;
- }
- #ifdef WOLFSSL_EARLY_DATA
- void wolfSSL_set_quic_early_data_enabled(WOLFSSL* ssl, int enabled)
- {
- /* This only has effect on server and when the handshake has
- * not started yet.
- * This function is part of the quictls/openssl API and does
- * not return any error, sadly. So we just ignore any
- * unsuccessful use. But we can produce some warnings.
- */
- if (!WOLFSSL_IS_QUIC(ssl)) {
- WOLFSSL_MSG("wolfSSL_set_quic_early_data_enabled: not a QUIC SSL");
- }
- else if (ssl->options.handShakeState != NULL_STATE) {
- WOLFSSL_MSG("wolfSSL_set_quic_early_data_enabled: handshake started");
- }
- else {
- wolfSSL_set_max_early_data(ssl, enabled ? UINT32_MAX : 0);
- }
- }
- #endif /* WOLFSSL_EARLY_DATA */
- int wolfSSL_quic_do_handshake(WOLFSSL* ssl)
- {
- int ret = WOLFSSL_SUCCESS;
- WOLFSSL_ENTER("wolfSSL_quic_do_handshake");
- if (!wolfSSL_is_quic(ssl)) {
- WOLFSSL_MSG("WOLFSSL_QUIC_DO_HANDSHAKE not a QUIC SSL");
- ret = WOLFSSL_FAILURE;
- goto cleanup;
- }
- while (ssl->options.handShakeState != HANDSHAKE_DONE) {
- /* Peculiar: do_handshake() is successful, but the state
- * indicates that we are not DONE. This seems to happen
- * when resuming sessions and an EARLY_DATA indicator
- * is presented by the client.
- * Theory: wolfSSL expects the APP to read the early data
- * and silently continues the handshake when the EndOfEarlyData
- * and the client Finished arrives.
- * This confuses the QUIC state handling.
- */
- #ifdef WOLFSSL_EARLY_DATA
- if (ssl->options.maxEarlyDataSz) {
- byte tmpbuffer[256];
- int len;
- if (ssl->options.side == WOLFSSL_CLIENT_END) {
- if (ssl->options.resuming) {
- ret = wolfSSL_write_early_data(ssl, tmpbuffer, 0, &len);
- }
- }
- else {
- ret = wolfSSL_read_early_data(ssl, tmpbuffer,
- sizeof(tmpbuffer), &len);
- if (ret < 0 && ssl->error == WC_NO_ERR_TRACE(ZERO_RETURN)) {
- /* this is expected, since QUIC handles the actual early
- * data separately. */
- ret = WOLFSSL_SUCCESS;
- }
- }
- if (ret < 0) {
- goto cleanup;
- }
- }
- #endif /* WOLFSSL_EARLY_DATA */
- ret = wolfSSL_SSL_do_handshake_internal(ssl);
- if (ret <= 0)
- goto cleanup;
- }
- cleanup:
- if (ret <= 0
- && ssl->options.handShakeState == HANDSHAKE_DONE
- && (ssl->error == WC_NO_ERR_TRACE(ZERO_RETURN) ||
- ssl->error == WC_NO_ERR_TRACE(WANT_READ)))
- {
- ret = WOLFSSL_SUCCESS;
- }
- if (ret == WOLFSSL_SUCCESS) {
- ssl->error = WOLFSSL_ERROR_NONE;
- }
- WOLFSSL_LEAVE("wolfSSL_quic_do_handshake", ret);
- return ret;
- }
- int wolfSSL_quic_read_write(WOLFSSL* ssl)
- {
- int ret = WOLFSSL_SUCCESS;
- WOLFSSL_ENTER("wolfSSL_quic_read_write");
- if (!wolfSSL_is_quic(ssl)) {
- WOLFSSL_MSG("WOLFSSL_QUIC_READ_WRITE not a QUIC SSL");
- ret = WOLFSSL_FAILURE;
- goto cleanup;
- }
- if (ssl->options.handShakeState != HANDSHAKE_DONE) {
- ret = wolfSSL_quic_do_handshake(ssl);
- if (ret != WOLFSSL_SUCCESS)
- goto cleanup;
- }
- ret = wolfSSL_process_quic_post_handshake(ssl);
- cleanup:
- WOLFSSL_LEAVE("wolfSSL_quic_read_write", ret);
- return ret;
- }
- int wolfSSL_process_quic_post_handshake(WOLFSSL* ssl)
- {
- int ret = WOLFSSL_SUCCESS, nret;
- WOLFSSL_ENTER("wolfSSL_process_quic_post_handshake");
- if (!wolfSSL_is_quic(ssl)) {
- WOLFSSL_MSG("WOLFSSL_QUIC_POST_HS not a QUIC SSL");
- ret = WOLFSSL_FAILURE;
- goto cleanup;
- }
- if (ssl->options.handShakeState != HANDSHAKE_DONE) {
- WOLFSSL_MSG("WOLFSSL_QUIC_POST_HS handshake is not done yet");
- ret = WOLFSSL_FAILURE;
- goto cleanup;
- }
- while (ssl->quic.input_head != NULL
- || ssl->buffers.inputBuffer.length > 0) {
- if ((nret = ProcessReply(ssl)) < 0) {
- ret = nret;
- break;
- }
- }
- while (ssl->buffers.outputBuffer.length > 0) {
- SendBuffered(ssl);
- }
- cleanup:
- WOLFSSL_LEAVE("wolfSSL_process_quic_post_handshake", ret);
- return ret;
- }
- int wolfSSL_provide_quic_data(WOLFSSL* ssl, WOLFSSL_ENCRYPTION_LEVEL level,
- const uint8_t* data, size_t len)
- {
- int ret = WOLFSSL_SUCCESS;
- size_t l;
- WOLFSSL_ENTER("wolfSSL_provide_quic_data");
- if (!wolfSSL_is_quic(ssl)) {
- WOLFSSL_MSG("WOLFSSL_QUIC_PROVIDE_DATA not a QUIC SSL");
- ret = WOLFSSL_FAILURE;
- goto cleanup;
- }
- if (level < wolfSSL_quic_read_level(ssl)
- || (ssl->quic.input_tail && level < ssl->quic.input_tail->level)
- || level < ssl->quic.enc_level_latest_recvd) {
- WOLFSSL_MSG("WOLFSSL_QUIC_PROVIDE_DATA wrong encryption level");
- ret = WOLFSSL_FAILURE;
- goto cleanup;
- }
- while (len > 0) {
- if (ssl->quic.scratch) {
- if (ssl->quic.scratch->level != level) {
- WOLFSSL_MSG("WOLFSSL_QUIC_PROVIDE_DATA wrong encryption level");
- ret = WOLFSSL_FAILURE;
- goto cleanup;
- }
- ret = quic_record_append(ssl, ssl->quic.scratch, data, len, &l);
- if (ret != WOLFSSL_SUCCESS) {
- goto cleanup;
- }
- data += l;
- len -= l;
- if (quic_record_complete(ssl->quic.scratch)) {
- if (ssl->quic.input_tail) {
- ssl->quic.input_tail->next = ssl->quic.scratch;
- ssl->quic.input_tail = ssl->quic.scratch;
- }
- else {
- ssl->quic.input_head = ssl->quic.input_tail =
- ssl->quic.scratch;
- }
- ssl->quic.scratch = NULL;
- }
- }
- else {
- /* start of next record with all bytes for the header */
- ssl->quic.scratch = quic_record_make(ssl, level, data, len);
- if (!ssl->quic.scratch) {
- ret = WOLFSSL_FAILURE;
- goto cleanup;
- }
- }
- }
- ssl->quic.enc_level_latest_recvd = level;
- cleanup:
- WOLFSSL_LEAVE("wolfSSL_provide_quic_data", ret);
- return ret;
- }
- /* Called internally when SSL wants a certain amount of input. */
- int wolfSSL_quic_receive(WOLFSSL* ssl, byte* buf, word32 sz)
- {
- sword32 n = 0;
- int transferred = 0;
- WOLFSSL_ENTER("wolfSSL_quic_receive");
- while (sz > 0) {
- n = 0;
- if (ssl->quic.input_head) {
- n = quic_record_transfer(ssl->quic.input_head, buf, sz);
- /* record too small to be fit into a RecordLayerHeader struct. */
- if (n == -1) {
- return WOLFSSL_FATAL_ERROR;
- }
- if (quic_record_done(ssl->quic.input_head)) {
- QuicRecord* qr = ssl->quic.input_head;
- ssl->quic.input_head = qr->next;
- if (!qr->next) {
- ssl->quic.input_tail = NULL;
- }
- quic_record_free(ssl, qr);
- }
- }
- if (n == 0) {
- if (transferred > 0) {
- goto cleanup;
- }
- ssl->error = transferred = WANT_READ;
- goto cleanup;
- }
- sz -= (word32)n;
- buf += n;
- transferred += (int)n;
- }
- cleanup:
- WOLFSSL_LEAVE("wolfSSL_quic_receive", transferred);
- return transferred;
- }
- /**
- * We need to forward the HANDSHAKE messages to the QUIC protocol stack
- * via ssl->quic.method->add_handshake_data().
- * The messages in the output buffer are unencrypted TLS records. We need
- * to forward the content of those records.
- */
- static int wolfSSL_quic_send_internal(WOLFSSL* ssl)
- {
- int ret = 0, aret;
- size_t len;
- RecordLayerHeader* rl;
- word16 rlen;
- word32 idx, length;
- byte* output;
- WOLFSSL_ENTER("wolfSSL_quic_send");
- idx = ssl->buffers.outputBuffer.idx;
- length = ssl->buffers.outputBuffer.length;
- output = ssl->buffers.outputBuffer.buffer + idx;
- while (length > 0) {
- if (ssl->quic.output_rec_remain > 0) {
- len = ssl->quic.output_rec_remain;
- if (len > length) {
- len = length;
- }
- aret = ssl->quic.method->add_handshake_data(ssl,
- ssl->quic.output_rec_level, (const uint8_t*)output, len);
- if (aret != 1) {
- /* The application has an error. General disaster. */
- WOLFSSL_MSG("WOLFSSL_QUIC_SEND application failed");
- ret = FWRITE_ERROR;
- goto cleanup;
- }
- output += len;
- length -= (word32)len;
- ssl->quic.output_rec_remain -= (word32)len;
- }
- else {
- /* at start of a TLS Record */
- rl = (RecordLayerHeader*)output;
- ato16(rl->length, &rlen);
- output += RECORD_HEADER_SZ;
- length -= RECORD_HEADER_SZ;
- ssl->quic.output_rec_remain = rlen;
- ssl->quic.output_rec_level = ssl->quic.enc_level_write;
- if (rl->type == application_data) {
- if (ssl->options.handShakeState != HANDSHAKE_DONE) {
- ssl->quic.output_rec_level = wolfssl_encryption_early_data;
- }
- else {
- WOLFSSL_MSG("WOLFSSL_QUIC_SEND app data after handshake");
- ret = FWRITE_ERROR;
- goto cleanup;
- }
- }
- }
- }
- ssl->buffers.outputBuffer.idx = 0;
- ssl->buffers.outputBuffer.length = 0;
- cleanup:
- WOLFSSL_LEAVE("wolfSSL_quic_send", ret);
- return ret;
- }
- int wolfSSL_quic_send(WOLFSSL* ssl)
- {
- return wolfSSL_quic_send_internal(ssl);
- }
- int wolfSSL_quic_forward_secrets(WOLFSSL* ssl, int ktype, int side)
- {
- const uint8_t* rx_secret = NULL, *tx_secret = NULL;
- WOLFSSL_ENCRYPTION_LEVEL level;
- int ret = 0;
- WOLFSSL_ENTER("wolfSSL_quic_forward_secrets");
- switch (ktype) {
- case early_data_key:
- level = wolfssl_encryption_early_data;
- break;
- case handshake_key:
- level = wolfssl_encryption_handshake;
- break;
- case traffic_key:
- FALL_THROUGH;
- case update_traffic_key:
- level = wolfssl_encryption_application;
- break;
- case no_key:
- FALL_THROUGH;
- default:
- /* ignore */
- goto cleanup;
- }
- if (side == ENCRYPT_AND_DECRYPT_SIDE || side == ENCRYPT_SIDE_ONLY) {
- tx_secret = (ssl->options.side == WOLFSSL_CLIENT_END) ?
- ssl->clientSecret : ssl->serverSecret;
- }
- if (side == ENCRYPT_AND_DECRYPT_SIDE || side == DECRYPT_SIDE_ONLY) {
- rx_secret = (ssl->options.side == WOLFSSL_CLIENT_END) ?
- ssl->serverSecret : ssl->clientSecret;
- }
- if (!tx_secret && !rx_secret) {
- WOLFSSL_MSG("WOLFSSL_QUIC_FORWARD_SECRETS neither "
- "enc- nor decrypt specified");
- goto cleanup;
- }
- ret = !ssl->quic.method->set_encryption_secrets(
- ssl, level, rx_secret, tx_secret, ssl->specs.hash_size);
- /* Having installed the secrets, any future read/write will happen
- * at the level. Except early data, which is detected on the record
- * type and the handshake state. */
- if (ktype == early_data_key) {
- goto cleanup;
- }
- if (tx_secret && ssl->quic.enc_level_write != level) {
- ssl->quic.enc_level_write_next = level;
- }
- if (rx_secret && ssl->quic.enc_level_read != level) {
- ssl->quic.enc_level_read_next = level;
- }
- cleanup:
- WOLFSSL_LEAVE("wolfSSL_quic_forward_secrets", ret);
- return ret;
- }
- int wolfSSL_quic_keys_active(WOLFSSL* ssl, enum encrypt_side side)
- {
- int ret = 0;
- WOLFSSL_ENTER("wolfSSL_quic_keys_active");
- /* Keys derived from recent secrets have been activated */
- if (side == ENCRYPT_AND_DECRYPT_SIDE || side == ENCRYPT_SIDE_ONLY) {
- /* If there is data in the output buffers, it was supposed to be
- * encrypted at the previous level. We need to remember that when
- * forwarding this data to the QUIC protocol application. */
- if (ssl->buffers.outputBuffer.length > 0) {
- ret = wolfSSL_quic_send_internal(ssl);
- if (ret)
- goto cleanup;
- }
- ssl->quic.enc_level_write = ssl->quic.enc_level_write_next;
- }
- if (side == ENCRYPT_AND_DECRYPT_SIDE || side == DECRYPT_SIDE_ONLY) {
- ssl->quic.enc_level_read = ssl->quic.enc_level_read_next;
- }
- cleanup:
- WOLFSSL_LEAVE("wolfSSL_quic_keys_active", ret);
- return ret;
- }
- const WOLFSSL_EVP_CIPHER* wolfSSL_quic_get_aead(WOLFSSL* ssl)
- {
- WOLFSSL_CIPHER* cipher = NULL;
- const WOLFSSL_EVP_CIPHER* evp_cipher = NULL;
- if (ssl == NULL) {
- return NULL;
- }
- cipher = wolfSSL_get_current_cipher(ssl);
- if (cipher == NULL) {
- return NULL;
- }
- switch (cipher->cipherSuite) {
- #if !defined(NO_AES) && defined(HAVE_AESGCM)
- case TLS_AES_128_GCM_SHA256:
- evp_cipher = wolfSSL_EVP_aes_128_gcm();
- break;
- case TLS_AES_256_GCM_SHA384:
- evp_cipher = wolfSSL_EVP_aes_256_gcm();
- break;
- #endif
- #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
- case TLS_CHACHA20_POLY1305_SHA256:
- evp_cipher = wolfSSL_EVP_chacha20_poly1305();
- break;
- #endif
- #if !defined(NO_AES) && defined(HAVE_AESCCM) && defined(WOLFSSL_AES_128)
- case TLS_AES_128_CCM_SHA256:
- evp_cipher = wolfSSL_EVP_aes_128_ccm();
- break;
- case TLS_AES_128_CCM_8_SHA256:
- WOLFSSL_MSG("wolfSSL_quic_get_aead: no CCM-8 support in EVP layer");
- evp_cipher = NULL;
- break;
- #endif
- default:
- evp_cipher = NULL;
- break;
- }
- if (!evp_cipher) {
- /* should not happen, as SSL* should not have negotiated it? */
- WOLFSSL_MSG("wolfSSL_quic_get_aead: current cipher not supported");
- return NULL;
- }
- return evp_cipher;
- }
- /* currently only used if HAVE_CHACHA && HAVE_POLY1305. */
- WC_MAYBE_UNUSED static int evp_cipher_eq(const WOLFSSL_EVP_CIPHER* c1,
- const WOLFSSL_EVP_CIPHER* c2)
- {
- /* We could check on nid equality, but we seem to have singulars */
- return c1 == c2;
- }
- const WOLFSSL_EVP_CIPHER* wolfSSL_quic_get_hp(WOLFSSL* ssl)
- {
- WOLFSSL_CIPHER* cipher = NULL;
- const WOLFSSL_EVP_CIPHER* evp_cipher = NULL;
- if (ssl == NULL) {
- return NULL;
- }
- cipher = wolfSSL_get_current_cipher(ssl);
- if (cipher == NULL) {
- return NULL;
- }
- switch (cipher->cipherSuite) {
- #if !defined(NO_AES) && defined(HAVE_AESGCM) && defined(WOLFSSL_AES_COUNTER)
- /* This has to be CTR even though the spec says that ECB is used for
- * mask generation. ngtcp2_crypto_hp_mask uses a hack where they pass
- * in the "ECB" input as the IV for the CTR cipher and then the input
- * is just a cleared buffer. They do this so that the EVP
- * init-update-final cycle can be used without the padding that is added
- * for EVP_aes_(128|256)_ecb. */
- #if defined(WOLFSSL_AES_128)
- case TLS_AES_128_GCM_SHA256:
- evp_cipher = wolfSSL_EVP_aes_128_ctr();
- break;
- #endif
- #if defined(WOLFSSL_AES_256)
- case TLS_AES_256_GCM_SHA384:
- evp_cipher = wolfSSL_EVP_aes_256_ctr();
- break;
- #endif
- #endif
- #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
- case TLS_CHACHA20_POLY1305_SHA256:
- evp_cipher = wolfSSL_EVP_chacha20();
- break;
- #endif
- #if !defined(NO_AES) && defined(HAVE_AESCCM) && defined(WOLFSSL_AES_128) && \
- defined(WOLFSSL_AES_COUNTER)
- /* This has to be CTR. See comment above. */
- case TLS_AES_128_CCM_SHA256:
- evp_cipher = wolfSSL_EVP_aes_128_ctr();
- break;
- case TLS_AES_128_CCM_8_SHA256:
- WOLFSSL_MSG("wolfSSL_quic_get_hp: no CCM-8 support in EVP layer");
- evp_cipher = NULL;
- break;
- #endif
- default:
- evp_cipher = NULL;
- break;
- }
- if (!evp_cipher) {
- /* should not happen, as SSL* should not have negotiated it? */
- WOLFSSL_MSG("wolfSSL_quic_get_hp: current cipher not supported");
- return NULL;
- }
- return evp_cipher;
- }
- size_t wolfSSL_quic_get_aead_tag_len(const WOLFSSL_EVP_CIPHER* aead_cipher)
- {
- size_t ret;
- #ifdef WOLFSSL_SMALL_STACK
- WOLFSSL_EVP_CIPHER_CTX *ctx = wolfSSL_EVP_CIPHER_CTX_new();
- if (ctx == NULL)
- return 0;
- #else
- WOLFSSL_EVP_CIPHER_CTX ctx[1];
- #endif
- XMEMSET(ctx, 0, sizeof(*ctx));
- if (wolfSSL_EVP_CipherInit(ctx, aead_cipher, NULL, NULL, 0)
- == WOLFSSL_SUCCESS) {
- ret = (size_t)ctx->authTagSz;
- } else {
- ret = 0;
- }
- (void)wolfSSL_EVP_CIPHER_CTX_cleanup(ctx);
- #ifdef WOLFSSL_SMALL_STACK
- XFREE(ctx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- #endif
- return ret;
- }
- int wolfSSL_quic_aead_is_gcm(const WOLFSSL_EVP_CIPHER* aead_cipher)
- {
- return WOLFSSL_EVP_CIPHER_mode(aead_cipher) == WOLFSSL_EVP_CIPH_GCM_MODE;
- }
- int wolfSSL_quic_aead_is_ccm(const WOLFSSL_EVP_CIPHER* aead_cipher)
- {
- return WOLFSSL_EVP_CIPHER_mode(aead_cipher) == WOLFSSL_EVP_CIPH_CCM_MODE;
- }
- int wolfSSL_quic_aead_is_chacha20(const WOLFSSL_EVP_CIPHER* aead_cipher)
- {
- #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
- return evp_cipher_eq(aead_cipher, wolfSSL_EVP_chacha20_poly1305());
- #else
- (void)aead_cipher;
- return 0;
- #endif
- }
- const WOLFSSL_EVP_MD* wolfSSL_quic_get_md(WOLFSSL* ssl)
- {
- /* a copy from the handshake md setup */
- switch(ssl->specs.mac_algorithm) {
- case no_mac:
- #ifndef NO_MD5
- case md5_mac:
- return wolfSSL_EVP_md5();
- #endif
- #ifndef NO_SHA
- case sha_mac:
- return wolfSSL_EVP_sha1();
- #endif
- #ifdef WOLFSSL_SHA224
- case sha224_mac:
- return wolfSSL_EVP_sha224();
- #endif
- case sha256_mac:
- return wolfSSL_EVP_sha256();
- #ifdef WOLFSSL_SHA384
- case sha384_mac:
- return wolfSSL_EVP_sha384();
- #endif
- #ifdef WOLFSSL_SHA512
- case sha512_mac:
- return wolfSSL_EVP_sha512();
- #endif
- case rmd_mac:
- case blake2b_mac:
- WOLFSSL_MSG("no suitable EVP_MD");
- return NULL;
- default:
- WOLFSSL_MSG("Unknown mac algorithm");
- return NULL;
- }
- }
- #ifdef OPENSSL_EXTRA
- int wolfSSL_quic_hkdf_extract(uint8_t* dest, const WOLFSSL_EVP_MD* md,
- const uint8_t* secret, size_t secretlen,
- const uint8_t* salt, size_t saltlen)
- {
- WOLFSSL_EVP_PKEY_CTX* pctx = NULL;
- size_t destlen = (size_t)wolfSSL_EVP_MD_size(md);
- int ret = WOLFSSL_SUCCESS;
- WOLFSSL_ENTER("wolfSSL_quic_hkdf_extract");
- pctx = wolfSSL_EVP_PKEY_CTX_new_id(NID_hkdf, NULL);
- if (pctx == NULL) {
- ret = WOLFSSL_FAILURE;
- goto cleanup;
- }
- if (wolfSSL_EVP_PKEY_derive_init(pctx) != WOLFSSL_SUCCESS
- || wolfSSL_EVP_PKEY_CTX_hkdf_mode(
- pctx, EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY) != WOLFSSL_SUCCESS
- || wolfSSL_EVP_PKEY_CTX_set_hkdf_md(pctx, md) != WOLFSSL_SUCCESS
- || wolfSSL_EVP_PKEY_CTX_set1_hkdf_salt(
- pctx, (byte*)salt, (int)saltlen) != WOLFSSL_SUCCESS
- || wolfSSL_EVP_PKEY_CTX_set1_hkdf_key(
- pctx, (byte*)secret, (int)secretlen) != WOLFSSL_SUCCESS
- || wolfSSL_EVP_PKEY_derive(pctx, dest, &destlen) != WOLFSSL_SUCCESS) {
- ret = WOLFSSL_FAILURE;
- goto cleanup;
- }
- cleanup:
- if (pctx)
- wolfSSL_EVP_PKEY_CTX_free(pctx);
- WOLFSSL_LEAVE("wolfSSL_quic_hkdf_extract", ret);
- return ret;
- }
- int wolfSSL_quic_hkdf_expand(uint8_t* dest, size_t destlen,
- const WOLFSSL_EVP_MD* md,
- const uint8_t* secret, size_t secretlen,
- const uint8_t* info, size_t infolen)
- {
- WOLFSSL_EVP_PKEY_CTX* pctx = NULL;
- int ret = WOLFSSL_SUCCESS;
- WOLFSSL_ENTER("wolfSSL_quic_hkdf_expand");
- pctx = wolfSSL_EVP_PKEY_CTX_new_id(NID_hkdf, NULL);
- if (pctx == NULL) {
- ret = WOLFSSL_FAILURE;
- goto cleanup;
- }
- if (wolfSSL_EVP_PKEY_derive_init(pctx) != WOLFSSL_SUCCESS
- || wolfSSL_EVP_PKEY_CTX_hkdf_mode(
- pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) != WOLFSSL_SUCCESS
- || wolfSSL_EVP_PKEY_CTX_set_hkdf_md(pctx, md) != WOLFSSL_SUCCESS
- || wolfSSL_EVP_PKEY_CTX_set1_hkdf_salt(
- pctx, (byte*)"", 0) != WOLFSSL_SUCCESS
- || wolfSSL_EVP_PKEY_CTX_set1_hkdf_key(
- pctx, (byte*)secret, (int)secretlen) != WOLFSSL_SUCCESS
- || wolfSSL_EVP_PKEY_CTX_add1_hkdf_info(
- pctx, (byte*)info, (int)infolen) != WOLFSSL_SUCCESS
- || wolfSSL_EVP_PKEY_derive(pctx, dest, &destlen) != WOLFSSL_SUCCESS) {
- ret = WOLFSSL_FAILURE;
- goto cleanup;
- }
- cleanup:
- if (pctx)
- EVP_PKEY_CTX_free(pctx);
- WOLFSSL_LEAVE("wolfSSL_quic_hkdf_expand", ret);
- return ret;
- }
- int wolfSSL_quic_hkdf(uint8_t* dest, size_t destlen,
- const WOLFSSL_EVP_MD* md,
- const uint8_t* secret, size_t secretlen,
- const uint8_t* salt, size_t saltlen,
- const uint8_t* info, size_t infolen)
- {
- WOLFSSL_EVP_PKEY_CTX* pctx = NULL;
- int ret = WOLFSSL_SUCCESS;
- WOLFSSL_ENTER("wolfSSL_quic_hkdf");
- pctx = wolfSSL_EVP_PKEY_CTX_new_id(NID_hkdf, NULL);
- if (pctx == NULL) {
- ret = WOLFSSL_FAILURE;
- goto cleanup;
- }
- if (wolfSSL_EVP_PKEY_derive_init(pctx) != WOLFSSL_SUCCESS
- || wolfSSL_EVP_PKEY_CTX_hkdf_mode(
- pctx, EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND) != WOLFSSL_SUCCESS
- || wolfSSL_EVP_PKEY_CTX_set_hkdf_md(pctx, md) != WOLFSSL_SUCCESS
- || wolfSSL_EVP_PKEY_CTX_set1_hkdf_salt(
- pctx, (byte*)salt, (int)saltlen) != WOLFSSL_SUCCESS
- || wolfSSL_EVP_PKEY_CTX_set1_hkdf_key(
- pctx, (byte*)secret, (int)secretlen) != WOLFSSL_SUCCESS
- || wolfSSL_EVP_PKEY_CTX_add1_hkdf_info(
- pctx, (byte*)info, (int)infolen) != WOLFSSL_SUCCESS
- || wolfSSL_EVP_PKEY_derive(pctx, dest, &destlen) != WOLFSSL_SUCCESS) {
- ret = WOLFSSL_FAILURE;
- goto cleanup;
- }
- cleanup:
- if (pctx)
- EVP_PKEY_CTX_free(pctx);
- WOLFSSL_LEAVE("wolfSSL_quic_hkdf", ret);
- return ret;
- }
- #endif /* OPENSSL_EXTRA */
- WOLFSSL_EVP_CIPHER_CTX* wolfSSL_quic_crypt_new(const WOLFSSL_EVP_CIPHER* cipher,
- const uint8_t* key,
- const uint8_t* iv,
- int encrypt)
- {
- WOLFSSL_EVP_CIPHER_CTX* ctx;
- ctx = wolfSSL_EVP_CIPHER_CTX_new();
- if (ctx == NULL) {
- return NULL;
- }
- if (wolfSSL_EVP_CipherInit(ctx, cipher, key, iv, encrypt)
- != WOLFSSL_SUCCESS) {
- wolfSSL_EVP_CIPHER_CTX_free(ctx);
- return NULL;
- }
- return ctx;
- }
- int wolfSSL_quic_aead_encrypt(uint8_t* dest, WOLFSSL_EVP_CIPHER_CTX* ctx,
- const uint8_t* plain, size_t plainlen,
- const uint8_t* iv, const uint8_t* aad,
- size_t aadlen)
- {
- int len;
- /* A case can be made if this really should be a function in wolfSSL, since
- * the same should be doable from the API by a QUIC protocol stack.
- * What speaks for this:
- * - it gives us a decent testing point
- * - API users do not have to re-invent (it fits into ngtcp2 use).
- * picotls offers a similar abstraction level for AEAD.
- * TODO: there is some fiddling in OpenSSL+quic in regard to CCM ciphers
- * which we need to check.
- */
- if (wolfSSL_EVP_CipherInit(ctx, NULL, NULL, iv, 1) != WOLFSSL_SUCCESS
- || wolfSSL_EVP_CipherUpdate(
- ctx, NULL, &len, aad, (int)aadlen) != WOLFSSL_SUCCESS
- || wolfSSL_EVP_CipherUpdate(
- ctx, dest, &len, plain, (int)plainlen) != WOLFSSL_SUCCESS
- || wolfSSL_EVP_CipherFinal(ctx, dest + len, &len) != WOLFSSL_SUCCESS
- || wolfSSL_EVP_CIPHER_CTX_ctrl(
- ctx, EVP_CTRL_AEAD_GET_TAG, ctx->authTagSz, dest + plainlen)
- != WOLFSSL_SUCCESS) {
- return WOLFSSL_FAILURE;
- }
- return WOLFSSL_SUCCESS;
- }
- int wolfSSL_quic_aead_decrypt(uint8_t* dest, WOLFSSL_EVP_CIPHER_CTX* ctx,
- const uint8_t* enc, size_t enclen,
- const uint8_t* iv, const uint8_t* aad,
- size_t aadlen)
- {
- int len;
- const uint8_t* tag;
- /* See rationale for wolfSSL_quic_aead_encrypt() on why this is here */
- if (enclen > INT_MAX || ctx->authTagSz > (int)enclen) {
- return WOLFSSL_FAILURE;
- }
- enclen -= (size_t)ctx->authTagSz;
- tag = enc + enclen;
- if (wolfSSL_EVP_CipherInit(ctx, NULL, NULL, iv, 0) != WOLFSSL_SUCCESS
- || wolfSSL_EVP_CIPHER_CTX_ctrl(
- ctx, EVP_CTRL_AEAD_SET_TAG, ctx->authTagSz, (uint8_t*)tag)
- != WOLFSSL_SUCCESS
- || wolfSSL_EVP_CipherUpdate(ctx, NULL, &len, aad, (int)aadlen)
- != WOLFSSL_SUCCESS
- || wolfSSL_EVP_CipherUpdate(ctx, dest, &len, enc, (int)enclen)
- != WOLFSSL_SUCCESS
- || wolfSSL_EVP_CipherFinal(ctx, dest, &len) != WOLFSSL_SUCCESS) {
- return WOLFSSL_FAILURE;
- }
- return WOLFSSL_SUCCESS;
- }
- #endif /* WOLFSSL_QUIC */
- #endif /* WOLFCRYPT_ONLY */
|