diff --git a/src/dtls13.c b/src/dtls13.c index c0b825b19..acc1a8686 100644 --- a/src/dtls13.c +++ b/src/dtls13.c @@ -31,6 +31,10 @@ #include #include #include +#include +#include +#include +#include #ifdef NO_INLINE #include @@ -39,6 +43,103 @@ #include #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; + +/** + * struct Dtls13RecordCiphertextHeader: represent the header of protected + * DTLSv1.3 used in wolfSSL + * @unifiedHdrflags: the first three bits are always 001, then CID bit: if + * setted the header contains a CID, S bit: if setted the header contains the 16 + * LSBs of sequence number length, otherwise only the 8 LSBs are present, then + * the L bit: if present the length of the record is present, lastly EE: the + * last two bits of the epoch + * @sequenceNumber: 16 LSBs of the sequence number + * @length: length of the record + * + * DTLSv1.3 uses a variable length header, this struct represent only the + * representation used by wolfSSL, where CID is never present (not supported), + * the 16 LSBs of the sequence number and the length are always present. + */ +typedef struct Dtls13RecordCiphertextHeader { + /* 0 0 1 C S L E E */ + byte unifiedHdrFlags; + byte sequenceNumber[2]; + byte length[2]; +} Dtls13RecordCiphertextHeader; + +/* size of the len field in the unified header */ +#define DTLS13_LEN_SIZE 2 +/* size of the mask used to encrypt/decrypt Record Number */ +#define DTLS13_RN_MASK_SIZE 16 +/* size of the flags in the unified header */ +#define DTLS13_HDR_FLAGS_SIZE 1 +/* size of the sequence number wher SEQ_LEN_BIT is present */ +#define DTLS13_SEQ_16_LEN 2 +/* size of the sequence number wher 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 + WOLFSSL_METHOD* wolfDTLSv1_3_client_method_ex(void* heap) { WOLFSSL_METHOD* method; @@ -79,6 +180,970 @@ WOLFSSL_METHOD* wolfDTLSv1_3_server_method(void) return wolfDTLSv1_3_server_method_ex(NULL); } +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) +{ + int ret = 0; + + switch (hs_type) { + case hello_request: + case hello_verify_request: + case client_hello: + case server_hello: + break; + case encrypted_extensions: + case session_ticket: + case end_of_early_data: + case hello_retry_request: + 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; + int ret; + + if (dir == PROTECT) + c = &ssl->dtlsRecordNumberEncrypt; + else + c = &ssl->dtlsRecordNumberDecrypt; + +#ifdef HAVE_AESGCM + if (ssl->specs.bulk_cipher_algorithm == wolfssl_aes_gcm) { + + if (c->aes == NULL) + return BAD_STATE_E; + return wc_AesEncryptDirect(c->aes, mask, ciphertext); + } +#endif /* HAVE_AESGCM */ + +#ifdef HAVE_CHACHA + if (ssl->specs.bulk_cipher_algorithm == wolfssl_chacha) { + word32 counter; + + 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. */ + XMEMCPY(&counter, ciphertext, sizeof(counter)); +#ifdef BIG_ENDIAN + counter = ByteReverseWord32(counter); +#endif /* BIG_ENDIAN */ + + 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; + + ret = Dtls13GetRnMask(ssl, ciphertext, mask, dir); + if (ret != 0) + return ret; + + xorbuf(seq, mask, SeqLength); + + return 0; +} + +static void Dtls13MsgWasProcessed(WOLFSSL* ssl, enum HandShakeType hs) +{ + (void)hs; + + ssl->keys.dtls_expected_peer_handshake_number++; +} + +static int Dtls13ProcessBufferedMessages(WOLFSSL* ssl) +{ + DtlsMsg* msg = ssl->dtls_rx_msg_list; + word32 idx = 0; + int ret = 0; + + WOLFSSL_ENTER("Dtls13ProcessBufferedMessages()"); + + while (msg != NULL) { + idx = 0; + + /* message not in order */ + if (ssl->keys.dtls_expected_peer_handshake_number != msg->seq) + break; + + /* message not complete */ + if (msg->fragSz != msg->sz) + break; + + ret = DoTls13HandShakeMsgType(ssl, msg->msg, &idx, msg->type, msg->sz, + msg->sz); + if (ret != 0) + break; + + Dtls13MsgWasProcessed(ssl, msg->type); + + ssl->dtls_rx_msg_list = msg->next; + DtlsMsgDelete(msg, ssl->heap); + msg = ssl->dtls_rx_msg_list; + ssl->dtls_rx_msg_list_sz--; + } + + 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->fragSz == ssl->dtls_rx_msg_list->sz && + 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 = ssl->buffers.outputBuffer.buffer + ssl->buffers.outputBuffer.length; + + XMEMCPY(buf, output, length); + + ssl->buffers.outputBuffer.length += length; + + return SendBuffered(ssl); +} + +static int Dtls13SendNow(WOLFSSL* ssl, enum HandShakeType handshakeType) +{ + if (!ssl->options.groupMessages) + return 1; + + if (handshakeType == client_hello || handshakeType == hello_retry_request || + handshakeType == finished || handshakeType == session_ticket || + handshakeType == session_ticket || handshakeType == key_update) + return 1; + + return 0; +} + +/* Handshake header DTLS only fields are not inlcuded in the transcript hash */ +int Dtls13HashHandshake(WOLFSSL* ssl, const byte* output, word16 length) +{ + int ret; + + if (length < DTLS_HANDSHAKE_HEADER_SZ) + return BAD_FUNC_ARG; + + /* msg_type(1) + length (3) */ + ret = HashRaw(ssl, output, OPAQUE32_LEN); + if (ret != 0) + return ret; + + output += OPAQUE32_LEN; + length -= OPAQUE32_LEN; + + /* message_seq(2) + fragment_offset(3) + fragment_length(3) */ + output += OPAQUE64_LEN; + length -= OPAQUE64_LEN; + + return HashRaw(ssl, output, 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(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_TEMP_BUFFER); + ssl->dtls13FragmentsBuffer.buffer = NULL; + ssl->dtls13SendingFragments = 0; + ssl->dtls13MessageLength = ssl->dtls13FragOffset = 0; +} + +static int Dtls13SendFragmentedInternal(WOLFSSL* ssl) +{ + int fragLength, rlHeaderLength; + int remainingSize, maxFragment; + int recordLength; + byte isEncrypted; + byte* output; + int ret; + + isEncrypted = Dtls13TypeIsEncrypted(ssl->dtls13FragHandshakeType); + rlHeaderLength = Dtls13GetRlHeaderLength(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) + return ret; + + output = + ssl->buffers.outputBuffer.buffer + ssl->buffers.outputBuffer.length; + + ret = Dtls13HandshakeAddHeaderFrag(ssl, output + rlHeaderLength, + 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 = Dtls13SendFragment(ssl, output, maxFragment, recordLength, + ssl->dtls13FragHandshakeType, 0, 1); + 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(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 - 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; +} + +/** + * 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) +{ + Dtls13RecordCiphertextHeader* hdr; + word16 seqNumber; + + if (out == NULL) + return BAD_FUNC_ARG; + + if (ssl->dtls13EncryptEpoch == NULL) + return BAD_STATE_E; + + hdr = (Dtls13RecordCiphertextHeader*)out; + + hdr->unifiedHdrFlags = DTLS13_FIXED_BITS; + hdr->unifiedHdrFlags |= + Dtls13GetEpochBits(ssl->dtls13EncryptEpoch->epochNumber); + + /* include 16-bit seq */ + hdr->unifiedHdrFlags |= DTLS13_SEQ_LEN_BIT; + /* include 16-bit length */ + hdr->unifiedHdrFlags |= DTLS13_LEN_BIT; + + seqNumber = (word16)w64GetLow32(ssl->dtls13EncryptEpoch->nextSeqNumber); + c16toa(seqNumber, hdr->sequenceNumber); + c16toa(length, hdr->length); + + 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; + + 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(1) + DTLS13_MIN_CIPHERTEXT) + return BUFFER_ERROR; + + seqLength = (*hdr & DTLS13_LEN_BIT) ? DTLS13_SEQ_16_LEN : DTLS13_SEQ_8_LEN; + + /* header flags + seq number */ + hdrLength = 1 + seqLength; + + /* length present */ + if (*hdr & DTLS13_LEN_BIT) + hdrLength += DTLS13_LEN_SIZE; + + return Dtls13EncryptDecryptRecordNumber(ssl, + /* seq number offset */ + hdr + 1, + /* 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(byte isEncrypted) +{ + /* the function looks useless but allow to support variable length unified + header in the future */ + if (!isEncrypted) + return DTLS_RECORD_HEADER_SZ; + + return DTLS13_UNIFIED_HEADER_SIZE; +} + +/** + * Dtls13GetHeadersLength() - return length of record + handshake header + * @type: type of handshake in the message + */ +word16 Dtls13GetHeadersLength(enum HandShakeType type) +{ + byte isEncrypted; + + isEncrypted = Dtls13TypeIsEncrypted(type); + + return Dtls13GetRlHeaderLength(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; + 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; +} + +/** + * 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; + word16 idx; + int ret; + + if (input == NULL || inputSize == 0) + return BAD_FUNC_ARG; + + if (*input & DTLS13_CID_BIT) { + WOLFSSL_MSG("DTLS1.3 header with connection ID. Not supported"); + return WOLFSSL_NOT_IMPLEMENTED; + } + + idx = DTLS13_HDR_FLAGS_SIZE; + + seqLen = (*input & DTLS13_SEQ_LEN_BIT) != 0 ? DTLS13_SEQ_16_LEN + : DTLS13_SEQ_8_LEN; + hasLength = *input & DTLS13_LEN_BIT; + hdrInfo->epochBits = *input & 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; + + /* DTLS message must fit inside a datagram */ + if (inputSize < idx + hdrInfo->recordLength) + return LENGTH_ERROR; + } + 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; + + seqNum = (byte*)(input + DTLS13_HDR_FLAGS_SIZE); + + ret = Dtls13EncryptDecryptRecordNumber(ssl, seqNum, seqLen, input + idx, + DEPROTECT); + if (ret != 0) + return ret; + + hdrInfo->headerLength = idx; + + 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) +{ + (void)ssl; + + 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 frag_off, frag_length; + byte isComplete, isFirst; + word32 message_length; + byte handshake_type; + word32 idx; + int ret; + + idx = 0; + ret = GetDtlsHandShakeHeader(ssl, input, &idx, &handshake_type, + &message_length, &frag_off, &frag_length, size); + if (ret != 0) + return PARSE_ERROR; + + if (idx + frag_length > size) { + WOLFSSL_ERROR(INCOMPLETE_DATA); + return INCOMPLETE_DATA; + } + + if (frag_off + frag_length > message_length) + return BUFFER_ERROR; + + 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 + frag_length; + + *processedSize += ssl->keys.padSz; + + return 0; + } + + isFirst = frag_off == 0; + isComplete = isFirst && frag_length == message_length; + + if (!isComplete || ssl->keys.dtls_peer_handshake_number > + ssl->keys.dtls_expected_peer_handshake_number) { + DtlsMsgStore(ssl, w64GetLow32(ssl->keys.curEpoch64), + ssl->keys.dtls_peer_handshake_number, + input + DTLS_HANDSHAKE_HEADER_SZ, message_length, handshake_type, + frag_off, frag_length, ssl->heap); + + *processedSize = idx + frag_length; + + *processedSize += ssl->keys.padSz; + + if (Dtls13NextMessageComplete(ssl)) + return Dtls13ProcessBufferedMessages(ssl); + + return 0; + } + + ret = DoTls13HandShakeMsgType(ssl, input, &idx, handshake_type, + message_length, size); + if (ret != 0) + return ret; + + Dtls13MsgWasProcessed(ssl, handshake_type); + + *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; + int isEncrypted; + + isEncrypted = Dtls13TypeIsEncrypted(hsType); + handshakeOffset = Dtls13GetRlHeaderLength(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; + + /* 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 (maxLen < maxFrag) { + ret = Dtls13SendFragment(ssl, message, outputSize, length, + handshakeType, hashOutput, Dtls13SendNow(ssl, handshakeType)); + + 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"; @@ -233,6 +1298,48 @@ static void Dtls13EpochCopyKeys(WOLFSSL* ssl, Dtls13Epoch* e, Keys* k, int side) 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 curent 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; diff --git a/src/internal.c b/src/internal.c index 70229f91d..3486d0be2 100644 --- a/src/internal.c +++ b/src/internal.c @@ -506,8 +506,16 @@ static WC_INLINE int IsEncryptionOn(WOLFSSL* ssl, int isSend) { #ifdef WOLFSSL_DTLS /* For DTLS, epoch 0 is always not encrypted. */ - if (ssl->options.dtls && !isSend && ssl->keys.curEpoch == 0) - return 0; + if (ssl->options.dtls && !isSend) { + if (!IsAtLeastTLSv1_3(ssl->version) && ssl->keys.curEpoch == 0) + return 0; +#ifdef WOLFSSL_DTLS13 + else if (IsAtLeastTLSv1_3(ssl->version) + && w64IsZero(ssl->keys.curEpoch64)) + return 0; +#endif /* WOLFSSL_DTLS13 */ + + } #endif /* WOLFSSL_DTLS */ return ssl->keys.encryptionOn && @@ -7425,8 +7433,8 @@ void FreeHandshakeResources(WOLFSSL* ssl) WOLFSSL_ENTER("FreeHandshakeResources"); #ifdef WOLFSSL_DTLS - /* DTLS_POOL */ - if (ssl->options.dtls) { + /* DTLS_POOL (DTLSv1.3 flushes the queue autonomously) */ + if (ssl->options.dtls && !IsAtLeastTLSv1_3(ssl->version)) { DtlsMsgPoolReset(ssl); DtlsMsgListDelete(ssl->dtls_rx_msg_list, ssl->heap); ssl->dtls_rx_msg_list = NULL; @@ -8759,8 +8767,19 @@ int HashOutput(WOLFSSL* ssl, const byte* output, int sz, int ivSz) #endif #ifdef WOLFSSL_DTLS if (ssl->options.dtls) { - adj += DTLS_RECORD_EXTRA; - sz -= DTLS_RECORD_EXTRA; + if (IsAtLeastTLSv1_3(ssl->version)) { +#ifdef WOLFSSL_DTLS13 + word16 dtls_record_extra; + dtls_record_extra = Dtls13GetRlHeaderLength(IsEncryptionOn(ssl, 1)); + dtls_record_extra -= RECORD_HEADER_SZ; + + adj += dtls_record_extra; + sz -= dtls_record_extra; +#endif /* WOLFSSL_DTLS13 */ + } else { + adj += DTLS_RECORD_EXTRA; + sz -= DTLS_RECORD_EXTRA; + } } #endif @@ -8784,6 +8803,12 @@ int HashInput(WOLFSSL* ssl, const byte* input, int sz) if (ssl->options.dtls) { adj -= DTLS_HANDSHAKE_EXTRA; sz += DTLS_HANDSHAKE_EXTRA; + +#ifdef WOLFSSL_DTLS13 + if (IsAtLeastTLSv1_3(ssl->version)) + return Dtls13HashHandshake(ssl, adj, sz); +#endif /* WOLFSSL_DTLS13 */ + } #endif @@ -9466,7 +9491,12 @@ int CheckAvailableSize(WOLFSSL *ssl, int size) #else ssl->dtls_expected_rx #endif - ) { +#ifdef WOLFSSL_DTLS13 + /* DTLS1.3 uses the output buffer to store the full message and deal + with fragmentation later in dtls13HandshakeSend() */ + && !IsAtLeastTLSv1_3(ssl->version) +#endif /* WOLFSSL_DTLS13 */ + ) { WOLFSSL_MSG("CheckAvailableSize() called with size greater than MTU."); return DTLS_SIZE_ERROR; } @@ -9482,15 +9512,171 @@ int CheckAvailableSize(WOLFSSL *ssl, int size) return 0; } +#ifdef WOLFSSL_DTLS13 +static int GetDtls13RecordHeader(WOLFSSL* ssl, const byte* input, + word32* inOutIdx, RecordLayerHeader* rh, word16* size) +{ + + Dtls13UnifiedHdrInfo hdrInfo; + w64wrapper epochNumber; + byte epochBits; + int readSize; + int ret; + + readSize = ssl->buffers.inputBuffer.length - *inOutIdx; + + epochBits = *input & EE_MASK; + ret = Dtls13ReconstructEpochNumber(ssl, epochBits, &epochNumber); + if (ret != 0) + return ret; + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG_EX("reconstructed epoch number: %ld", + epochNumber); +#endif /* WOLFSSL_DEBUG_TLS */ + + /* protected records always use unified_headers in DTLSv1.3 */ + if (w64IsZero(epochNumber)) + return SEQUENCE_ERROR; + + if (ssl->dtls13DecryptEpoch == NULL) + return BAD_STATE_E; + +#ifdef WOLFSSL_EARLY_DATA + if (w64Equal(epochNumber, w64From32(0x0, DTLS13_EPOCH_EARLYDATA)) && + ssl->options.handShakeDone) { + WOLFSSL_MSG("discarding early data after handshake"); + return SEQUENCE_ERROR; + } +#endif /* WOLFSSL_DTLS13 */ + + if (!w64Equal(ssl->dtls13DecryptEpoch->epochNumber, epochNumber)) { + ret = Dtls13SetEpochKeys(ssl, epochNumber, DECRYPT_SIDE_ONLY); + if (ret != 0) + return SEQUENCE_ERROR; + } + + ret = Dtls13ParseUnifiedRecordLayer(ssl, input + *inOutIdx, readSize, + &hdrInfo); + + if (ret != 0) + return ret; + + *size = hdrInfo.recordLength; + c16toa(*size, rh->length); + + /* type is implicit */ + rh->type = application_data; + + /* version is implicit */ + rh->pvMajor = ssl->version.major; + rh->pvMinor = DTLSv1_2_MINOR; + + ssl->keys.curEpoch64 = epochNumber; + + ret = Dtls13ReconstructSeqNumber(ssl, &hdrInfo, &ssl->keys.curSeq); + if (ret != 0) + return ret; + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG_EX("reconstructed seq number: %ld", + ssl->keys.curSeq); +#endif /* WOLFSSL_DEBUG_TLS */ + + *inOutIdx += hdrInfo.headerLength; + ssl->dtls13CurRlLength = hdrInfo.headerLength; + + return 0; +} + +#endif /* WOLFSSL_DTLS13 */ + +#ifdef WOLFSSL_DTLS +static int GetDtlsRecordHeader(WOLFSSL* ssl, const byte* input, + word32* inOutIdx, RecordLayerHeader* rh, word16* size) +{ + +#ifdef HAVE_FUZZER + if (ssl->fuzzerCb) + ssl->fuzzerCb(ssl, input + *inOutIdx, DTLS_RECORD_HEADER_SZ, + FUZZ_HEAD, ssl->fuzzerCtx); +#endif + +#ifdef WOLFSSL_DTLS13 + word32 read_size; + + read_size = ssl->buffers.inputBuffer.length - *inOutIdx; + + if (Dtls13IsUnifiedHeader(*(input + *inOutIdx))) { + + /* version 1.3 already negotiated */ + if (ssl->options.tls1_3) + return GetDtls13RecordHeader(ssl, input, inOutIdx, rh, size); + + } + + /* not a unified header, check that we have at least + DTLS_RECORD_HEADER_SZ */ + if (read_size < DTLS_RECORD_HEADER_SZ) + return LENGTH_ERROR; + +#endif /* WOLFSSL_DTLS13 */ + + /* type and version in same spot */ + XMEMCPY(rh, input + *inOutIdx, ENUM_LEN + VERSION_SZ); + *inOutIdx += ENUM_LEN + VERSION_SZ; + ato16(input + *inOutIdx, &ssl->keys.curEpoch); +#ifdef WOLFSSL_DTLS13 + /* only non protected message can use the DTLSPlaintext record header */ + if (ssl->options.tls1_3 && ssl->keys.curEpoch != 0) + return SEQUENCE_ERROR; + + w64Zero(&ssl->keys.curEpoch64); + if (!w64IsZero(ssl->dtls13DecryptEpoch->epochNumber)) + Dtls13SetEpochKeys(ssl, ssl->keys.curEpoch64, DECRYPT_SIDE_ONLY); + +#endif /* WOLFSSL_DTLS13 */ + *inOutIdx += OPAQUE16_LEN; + if (ssl->options.haveMcast) { + #ifdef WOLFSSL_MULTICAST + ssl->keys.curPeerId = input[*inOutIdx]; + ssl->keys.curSeq_hi = input[*inOutIdx+1]; + #endif + } + else + ato16(input + *inOutIdx, &ssl->keys.curSeq_hi); + *inOutIdx += OPAQUE16_LEN; + ato32(input + *inOutIdx, &ssl->keys.curSeq_lo); + *inOutIdx += OPAQUE32_LEN; /* advance past rest of seq */ + +#ifdef WOLFSSL_DTLS13 + /* DTLSv1.3 PlainText records use DTLSv1.2 sequence number encoding. Update + the DTLv1.3 word64 version as well */ + ssl->keys.curSeq = w64From32(ssl->keys.curSeq_hi, ssl->keys.curSeq_lo); +#endif /* WOLFSSL_DTLS13 */ + + ato16(input + *inOutIdx, size); + *inOutIdx += LENGTH_SZ; + + return 0; +} +#endif /* WOLFSSL_DTLS */ /* do all verify and sanity checks on record header */ static int GetRecordHeader(WOLFSSL* ssl, const byte* input, word32* inOutIdx, RecordLayerHeader* rh, word16 *size) { byte tls12minor; +#ifdef WOLFSSL_DTLS + int ret; +#endif /* WOLFSSL_DTLS */ + #ifdef OPENSSL_ALL word32 start = *inOutIdx; #endif + + (void)tls12minor; + if (!ssl->options.dtls) { #ifdef HAVE_FUZZER if (ssl->fuzzerCb) @@ -9503,34 +9689,16 @@ static int GetRecordHeader(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } else { #ifdef WOLFSSL_DTLS -#ifdef HAVE_FUZZER - if (ssl->fuzzerCb) - ssl->fuzzerCb(ssl, input + *inOutIdx, DTLS_RECORD_HEADER_SZ, - FUZZ_HEAD, ssl->fuzzerCtx); -#endif - /* type and version in same sport */ - XMEMCPY(rh, input + *inOutIdx, ENUM_LEN + VERSION_SZ); - *inOutIdx += ENUM_LEN + VERSION_SZ; - ato16(input + *inOutIdx, &ssl->keys.curEpoch); - *inOutIdx += OPAQUE16_LEN; - if (ssl->options.haveMcast) { - #ifdef WOLFSSL_MULTICAST - ssl->keys.curPeerId = input[*inOutIdx]; - ssl->keys.curSeq_hi = input[*inOutIdx+1]; - #endif - } - else - ato16(input + *inOutIdx, &ssl->keys.curSeq_hi); - *inOutIdx += OPAQUE16_LEN; - ato32(input + *inOutIdx, &ssl->keys.curSeq_lo); - *inOutIdx += OPAQUE32_LEN; /* advance past rest of seq */ - ato16(input + *inOutIdx, size); - *inOutIdx += LENGTH_SZ; + ret = GetDtlsRecordHeader(ssl, input, inOutIdx, rh, size); + if (ret != 0) + return ret; #endif } #ifdef WOLFSSL_DTLS - if (IsDtlsNotSctpMode(ssl)) { + /* DTLSv1.3 MUST check window after deprotecting to avoid timing channel + (RFC9147 Section 4.5.1) */ + if (IsDtlsNotSctpMode(ssl) && !IsAtLeastTLSv1_3(ssl->version)) { if (!DtlsCheckWindow(ssl) || (rh->type == application_data && ssl->keys.curEpoch == 0) || (rh->type == alert && ssl->options.handShakeDone && @@ -14904,6 +15072,51 @@ static WC_INLINE int DtlsCheckWindow(WOLFSSL* ssl) return 1; } +#ifdef WOLFSSL_DTLS13 +static WC_INLINE int Dtls13CheckWindow(WOLFSSL* ssl) +{ + w64wrapper nextSeq, seq; + w64wrapper diff64; + word32 *window; + int wordOffset; + int wordIndex; + word32 diff; + + if (ssl->dtls13DecryptEpoch == NULL) { + WOLFSSL_MSG("Can't find decrypting epoch"); + return 0; + } + + nextSeq = ssl->dtls13DecryptEpoch->nextPeerSeqNumber; + window = ssl->dtls13DecryptEpoch->window; + seq = ssl->keys.curSeq; + + if (w64GTE(seq, nextSeq)) + return 1; + + /* seq < nextSeq, nextSeq - seq */ + diff64 = w64Sub(nextSeq, seq); + + /* diff >= DTLS_SEQ_BITS, outside of the window */ + if (w64GT(diff64, w64From32(0, DTLS_SEQ_BITS))) + return 0; + + /* we are assuming DTLS_SEQ_BITS <= 2**32 */ + diff = w64GetLow32(diff64); + + /* zero based index */ + diff--; + + wordIndex = ((int)diff) / DTLS_WORD_BITS; + wordOffset = ((int)diff) % DTLS_WORD_BITS; + + if (window[wordIndex] & (1 << wordOffset)) + return 0; + + return 1; +} + +#endif /* WOLFSSL_DTLS13 */ #ifdef WOLFSSL_MULTICAST static WC_INLINE word32 UpdateHighwaterMark(word32 cur, word32 first, @@ -15050,6 +15263,60 @@ static WC_INLINE int DtlsUpdateWindow(WOLFSSL* ssl) return _DtlsUpdateWindow(ssl, next_hi, next_lo, window); } +#ifdef WOLFSSL_DTLS13 +static WC_INLINE int Dtls13UpdateWindow(WOLFSSL* ssl) +{ + w64wrapper nextSeq, seq; + w64wrapper diff64; + word32 *window; + int wordOffset; + int wordIndex; + word32 diff; + + if (ssl->dtls13DecryptEpoch == NULL) { + WOLFSSL_MSG("Can't find decrypting Epoch"); + return BAD_STATE_E; + } + + nextSeq = ssl->dtls13DecryptEpoch->nextPeerSeqNumber; + window = ssl->dtls13DecryptEpoch->window; + seq = ssl->keys.curSeq; + + /* seq < nextSeq */ + if (w64LT(seq, nextSeq)) { + diff64 = w64Sub(nextSeq, seq); + + /* zero based index */ + w64Decrement(&diff64); + + /* FIXME: check that diff64 < DTLS_WORDS_BITS */ + diff = w64GetLow32(diff64); + wordIndex = ((int)diff) / DTLS_WORD_BITS; + wordOffset = ((int)diff) % DTLS_WORD_BITS; + + if (wordIndex >= WOLFSSL_DTLS_WINDOW_WORDS) { + WOLFSSL_MSG("Invalid sequence number to Dtls13UpdateWindow"); + return BAD_STATE_E; + } + + window[wordIndex] |= (1 << wordOffset); + return 1; + } + + /* seq >= nextSeq, seq - nextSeq */ + diff64 = w64Sub(seq, nextSeq); + + /* as we are considering nextSeq inside the window, we should add + 1 */ + w64Increment(&diff64); + DtlsUpdateWindowGTSeq(w64GetLow32(diff64), window); + + w64Increment(&seq); + ssl->dtls13DecryptEpoch->nextPeerSeqNumber = seq; + + return 1; +} +#endif /* WOLFSSL_DTLS13 */ + int DtlsMsgDrain(WOLFSSL* ssl) { @@ -17468,8 +17735,15 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) readSz = RECORD_HEADER_SZ; #ifdef WOLFSSL_DTLS - if (ssl->options.dtls) + if (ssl->options.dtls) { readSz = DTLS_RECORD_HEADER_SZ; +#ifdef WOLFSSL_DTLS13 + if (ssl->options.tls1_3) { + /* dtls1.3 unified header can be as little as 2 bytes */ + readSz = DTLS_UNIFIED_HEADER_MIN_SZ; + } +#endif /* WOLFSSL_DTLS13 */ + } #endif /* get header or return error */ @@ -17565,6 +17839,11 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) /* get the record layer header */ case getRecordLayerHeader: + /* DTLSv1.3 record numbers in the header are encrypted, and AAD + * uses the unecrypted form. Because of this we need to modify the + * header, decrypting the numbers inside + * DtlsParseUnifiedRecordLayer(). This violates the const attribute + * of the buffer parameter of GetRecordHeader() used here. */ ret = GetRecordHeader(ssl, ssl->buffers.inputBuffer.buffer, &ssl->buffers.inputBuffer.idx, &ssl->curRL, &ssl->curSize); @@ -17785,11 +18064,22 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) else { #ifdef WOLFSSL_TLS13 + byte *aad = (byte*)&ssl->curRL; + word16 aad_size = RECORD_HEADER_SZ; +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + /* aad now points to the record header */ + aad = in->buffer + + in->idx - ssl->dtls13CurRlLength; + aad_size = ssl->dtls13CurRlLength; + } +#endif /* WOLFSSL_DTLS13 */ + ret = DecryptTls13(ssl, in->buffer + in->idx, in->buffer + in->idx, ssl->curSize, - (byte*)&ssl->curRL, RECORD_HEADER_SZ, 1); + aad, aad_size, 1); #else ret = DECRYPT_ERROR; #endif /* WOLFSSL_TLS13 */ @@ -17816,6 +18106,15 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) else { WOLFSSL_MSG("Decrypt failed"); WOLFSSL_ERROR(ret); +#ifdef WOLFSSL_DTLS13 + if (ssl->options.tls1_3 && ssl->options.dtls) { + WOLFSSL_MSG("DTLS: Ignoring decrypted failed record"); + ssl->options.processReply = doProcessInit; + ssl->buffers.inputBuffer.idx = + ssl->buffers.inputBuffer.length; + return 0; + } +#endif /* WOLFSSL_DTLS13 */ #ifdef WOLFSSL_EARLY_DATA if (ssl->options.tls1_3) { if (ssl->options.side == WOLFSSL_SERVER_END && @@ -17936,6 +18235,35 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) /* the record layer is here */ case runProcessingOneRecord: +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version)) { + + if(!Dtls13CheckWindow(ssl)) { + /* drop packet */ + WOLFSSL_MSG( + "Dropping DTLS record outside receiving window"); + ssl->options.processReply = doProcessInit; + ssl->buffers.inputBuffer.idx += ssl->curSize; + if (ssl->buffers.inputBuffer.idx > + ssl->buffers.inputBuffer.length) + return BUFFER_E; + + continue; + } + + ret = Dtls13UpdateWindow(ssl); + if (ret != 1) { + WOLFSSL_ERROR(ret); + return ret; + } + + ret = Dtls13RecordRecvd(ssl); + if (ret != 0) { + WOLFSSL_ERROR(ret); + return ret; + } + } +#endif /* WOLFSSL_DTLS13 */ ssl->options.processReply = runProcessingOneMessage; FALL_THROUGH; @@ -17986,7 +18314,7 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) } #ifdef WOLFSSL_DTLS - if (IsDtlsNotSctpMode(ssl)) { + if (IsDtlsNotSctpMode(ssl) && !IsAtLeastTLSv1_3(ssl->version)) { DtlsUpdateWindow(ssl); } #endif /* WOLFSSL_DTLS */ @@ -17999,11 +18327,36 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) /* debugging in DoHandShakeMsg */ if (ssl->options.dtls) { #ifdef WOLFSSL_DTLS - ret = DoDtlsHandShakeMsg(ssl, - ssl->buffers.inputBuffer.buffer, - &ssl->buffers.inputBuffer.idx, - ssl->buffers.inputBuffer.length); + if (!IsAtLeastTLSv1_3(ssl->version)) { + ret = DoDtlsHandShakeMsg(ssl, + ssl->buffers.inputBuffer.buffer, + &ssl->buffers.inputBuffer.idx, + ssl->buffers.inputBuffer.length); + } #endif +#ifdef WOLFSSL_DTLS13 + if (IsAtLeastTLSv1_3(ssl->version)) { + ret = Dtls13HandshakeRecv(ssl, + ssl->buffers.inputBuffer.buffer, + &ssl->buffers.inputBuffer.idx, + ssl->buffers.inputBuffer.length); +#ifdef WOLFSSL_EARLY_DATA + if (ret == 0 && + ssl->options.side == WOLFSSL_SERVER_END && + ssl->earlyData > early_data_ext && + ssl->options.handShakeState == HANDSHAKE_DONE) { + + /* return so wolfSSL_read_early_data can return + exit */ + ssl->earlyData = no_early_data; + ssl->options.processReply = doProcessInit; + + return ZERO_RETURN; + } +#endif /* WOLFSSL_EARLY_DATA */ + + } +#endif /* WOLFSSL_DTLS13 */ } else if (!IsAtLeastTLSv1_3(ssl->version) #if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_TLS12) @@ -20497,6 +20850,42 @@ int SendData(WOLFSSL* ssl, const void* data, int sz) byte comp[MAX_RECORD_SIZE + MAX_COMP_EXTRA]; #endif +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls && ssl->options.tls1_3) { + byte isEarlyData = 0; + + if (ssl->dtls13EncryptEpoch == NULL) + return ssl->error = BAD_STATE_E; + +#ifdef WOLFSSL_EARLY_DATA + isEarlyData = ssl->earlyData != no_early_data; +#endif + + if (isEarlyData) { +#ifdef WOLFSSL_EARLY_DATA + ret = Dtls13SetEpochKeys(ssl, + w64From32(0x0, DTLS13_EPOCH_EARLYDATA), ENCRYPT_SIDE_ONLY); + if (ret != 0) { + WOLFSSL_MSG( + "trying to send early data without epoch 1"); + ssl->error = BUILD_MSG_ERROR; + return WOLFSSL_FATAL_ERROR; + } +#endif /* WOLFSSL_EARLY_DATA */ + } + else if (!w64Equal( + ssl->dtls13EncryptEpoch->epochNumber, + ssl->dtls13Epoch)) { + ret = Dtls13SetEpochKeys( + ssl, ssl->dtls13Epoch, ENCRYPT_SIDE_ONLY); + if (ret != 0) { + ssl->error = BUILD_MSG_ERROR; + return WOLFSSL_FATAL_ERROR; + } + } + } +#endif /* WOLFSSL_DTLS13 */ + #ifdef WOLFSSL_DTLS if (ssl->options.dtls) { buffSz = wolfSSL_GetMaxFragSize(ssl, sz - sent); @@ -20840,12 +21229,33 @@ static int SendAlert_ex(WOLFSSL* ssl, int severity, int type) * TLS 1.3 encrypts handshake packets after the ServerHello */ if (IsEncryptionOn(ssl, 1)) { +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls + && IsAtLeastTLSv1_3(ssl->version) + && !w64Equal(ssl->dtls13EncryptEpoch->epochNumber, ssl->dtls13Epoch)) { + ret = Dtls13SetEpochKeys(ssl, ssl->dtls13Epoch, ENCRYPT_SIDE_ONLY); + if (ret != 0) + return ret; + } +#endif /* WOLFSSL_DTLS13 */ + sendSz = BuildMessage(ssl, output, outputSz, input, ALERT_SIZE, alert, 0, 0, 0, CUR_ORDER); } else { - AddRecordHeader(output, ALERT_SIZE, alert, ssl, CUR_ORDER); +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version)) { + ret = Dtls13RlAddPlaintextHeader(ssl, output, alert, ALERT_SIZE); + if (ret != 0) + return ret; + } + else +#endif /* WOLFSSL_DTLS13 */ + { + AddRecordHeader(output, ALERT_SIZE, alert, ssl, CUR_ORDER); + } + output += RECORD_HEADER_SZ; #ifdef WOLFSSL_DTLS if (ssl->options.dtls) diff --git a/src/keys.c b/src/keys.c index e07300628..672f074ed 100644 --- a/src/keys.c +++ b/src/keys.c @@ -2081,6 +2081,15 @@ int SetCipherSpecs(WOLFSSL* ssl) #endif } +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls && + ssl->version.major == DTLS_MAJOR && + ssl->version.minor <= DTLSv1_3_MINOR) { + ssl->options.tls = 1; + ssl->options.tls1_3 = 1; + } +#endif /* WOLFSSL_DTLS13 */ + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) if (IsAtLeastTLSv1_3(ssl->version) || ssl->specs.cipher_type != block) ssl->options.encThenMac = 0; @@ -2966,7 +2975,7 @@ int SetKeysSide(WOLFSSL* ssl, enum encrypt_side side) #ifdef HAVE_SECURE_RENEGOTIATION #ifdef WOLFSSL_DTLS - if (ret == 0 && ssl->options.dtls) { + if (ret == 0 && ssl->options.dtls && !ssl->options.tls1_3) { if (wc_encrypt) wc_encrypt->src = keys == &ssl->keys ? KEYS : SCR; if (wc_decrypt) diff --git a/src/tls13.c b/src/tls13.c index b1200b88b..e1522f19c 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -1646,6 +1646,18 @@ static void AddTls13HandShakeHeader(byte* output, word32 length, (void)fragLength; (void)ssl; +#ifdef WOLFSSL_DTLS13 + /* message_hash type is used for a syntetic message that replaces the first + ClientHello in the hash transcript when using HelloRetryRequest. It will + never be transmitted and, as the DTLS-only fields must not be considered + when computing the hash transcript, we can avoid to use the DTLS + handshake header. */ + if (ssl->options.dtls && type != message_hash) { + Dtls13HandshakeAddHeader(ssl, output, type, length); + return; + } +#endif /* WOLFSSL_DTLS13 */ + /* handshake header */ hs = (HandShakeHeader*)output; hs->type = type; @@ -1666,6 +1678,13 @@ static void AddTls13Headers(byte* output, word32 length, byte type, word32 lengthAdj = HANDSHAKE_HEADER_SZ; word32 outputAdj = RECORD_HEADER_SZ; +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + Dtls13AddHeaders(output, length, type, ssl); + return; + } +#endif /* WOLFSSL_DTLS13 */ + AddTls13RecordHeader(output, length + lengthAdj, handshake, ssl); AddTls13HandShakeHeader(output + outputAdj, length, 0, length, type, ssl); } @@ -1688,6 +1707,15 @@ static void AddTls13FragHeaders(byte* output, word32 fragSz, word32 fragOffset, word32 outputAdj = RECORD_HEADER_SZ; (void)fragSz; +#ifdef WOLFSSL_DTLS13 + /* we ignore fragmentation fields here because fragmentation logic for + DTLS1.3 is inside dtls13_handshake_send(). */ + if (ssl->options.dtls) { + Dtls13AddHeaders(output, length, type, ssl); + return; + } +#endif /* WOLFSSL_DTLS13 */ + AddTls13RecordHeader(output, fragSz + lengthAdj, handshake, ssl); AddTls13HandShakeHeader(output + outputAdj, length, fragOffset, fragSz, type, ssl); @@ -1705,7 +1733,12 @@ static WC_INLINE void WriteSEQTls13(WOLFSSL* ssl, int verifyOrder, byte* out) { word32 seq[2] = {0, 0}; - if (verifyOrder) { + if (ssl->options.dtls) { +#ifdef WOLFSSL_DTLS13 + Dtls13GetSeq(ssl, verifyOrder, seq, 1); +#endif /* WOLFSSL_DTLS13 */ + } + else if (verifyOrder) { seq[0] = ssl->keys.peer_sequence_number_hi; seq[1] = ssl->keys.peer_sequence_number_lo++; /* handle rollover */ @@ -2419,9 +2452,15 @@ int BuildTls13Message(WOLFSSL* ssl, byte* output, int outSz, const byte* input, ssl->options.buildMsgState = BUILD_MSG_BEGIN; XMEMSET(args, 0, sizeof(BuildMsg13Args)); - args->sz = RECORD_HEADER_SZ + inSz; - args->idx = RECORD_HEADER_SZ; args->headerSz = RECORD_HEADER_SZ; +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) + args->headerSz = Dtls13GetRlHeaderLength(1); +#endif /* WOLFSSL_DTLS13 */ + + args->sz = args->headerSz + inSz; + args->idx = args->headerSz; + #ifdef WOLFSSL_ASYNC_CRYPT if (asyncOkay) ssl->async->freeArgs = FreeBuildMsg13Args; @@ -2462,7 +2501,15 @@ int BuildTls13Message(WOLFSSL* ssl, byte* output, int outSz, const byte* input, * Always have the content type as application data for encrypted * messages in TLS v1.3. */ - AddTls13RecordHeader(output, args->size, application_data, ssl); + + if (ssl->options.dtls) { +#ifdef WOLFSSL_DTLS13 + Dtls13RlAddCiphertextHeader(ssl, output, args->size); +#endif /* WOLFSSL_DTLS13 */ + } + else { + AddTls13RecordHeader(output, args->size, application_data, ssl); + } /* TLS v1.3 can do in place encryption. */ if (input != output + args->idx) @@ -2505,7 +2552,13 @@ int BuildTls13Message(WOLFSSL* ssl, byte* output, int outSz, const byte* input, const byte* aad = output; output += args->headerSz; ret = EncryptTls13(ssl, output, output, args->size, aad, - RECORD_HEADER_SZ, asyncOkay); + args->headerSz, asyncOkay); +#ifdef WOLFSSL_DTLS13 + if (ret == 0 && ssl->options.dtls) { + /* AAD points to the header. Reuse the variable */ + ret = Dtls13EncryptRecordNumber(ssl, (byte*)aad, args->sz); + } +#endif /* WOLFSSL_DTLS13 */ } break; } @@ -2671,6 +2724,8 @@ static int CreateCookie(WOLFSSL* ssl, byte* hash, byte hashSz) } #endif +#define HRR_MAX_HS_HEADER_SZ HANDSHAKE_HEADER_SZ + /* Restart the handshake hash with a hash of the previous messages. * * ssl The SSL/TLS object. @@ -2680,7 +2735,7 @@ int RestartHandshakeHash(WOLFSSL* ssl) { int ret; Hashes hashes; - byte header[HANDSHAKE_HEADER_SZ] = {0}; + byte header[HRR_MAX_HS_HEADER_SZ] = {0}; byte* hash = NULL; byte hashSz = 0; @@ -3025,7 +3080,14 @@ static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx) idx -= len; /* Hash truncated ClientHello - up to binders. */ - ret = HashOutput(ssl, output, idx, 0); +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) + ret = Dtls13HashHandshake(ssl, output + Dtls13GetRlHeaderLength(0), + idx - Dtls13GetRlHeaderLength(0)); + else +#endif /* WOLFSSL_DTLS13 */ + ret = HashOutput(ssl, output, idx, 0); + if (ret != 0) return ret; @@ -3084,6 +3146,16 @@ static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx) return ret; if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) return ret; + +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + ret = Dtls13NewEpoch( + ssl, w64From32(0x0, DTLS13_EPOCH_EARLYDATA), ENCRYPT_SIDE_ONLY); + if (ret != 0) + return ret; + } +#endif /* WOLFSSL_DTLS13 */ + } #endif @@ -3191,8 +3263,14 @@ int SendTls13ClientHello(WOLFSSL* ssl) switch (ssl->options.asyncState) { case TLS_ASYNC_BEGIN: { + args->idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) + args->idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; +#endif /* WOLFSSL_DTLS13 */ + /* Version | Random | Session Id | Cipher Suites | Compression */ args->length = VERSION_SZ + RAN_LEN + ENUM_LEN + ssl->suites->suiteSz + SUITE_LEN + COMP_LEN + ENUM_LEN; @@ -3203,6 +3281,12 @@ int SendTls13ClientHello(WOLFSSL* ssl) args->length += ssl->session->sessionIDSz; #endif +#ifdef WOLFSSL_DTLS13 + /* legacy_cookie_id (always 0 length) */ + if (ssl->options.dtls) + args->length += OPAQUE8_LEN; +#endif /* WOLFSSL_DTLS13 */ + /* Advance state and proceed */ ssl->options.asyncState = TLS_ASYNC_BUILD; } /* case TLS_ASYNC_BEGIN */ @@ -3248,6 +3332,11 @@ int SendTls13ClientHello(WOLFSSL* ssl) /* Total message size. */ args->sendSz = args->length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) + args->sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; +#endif /* WOLFSSL_DTLS13 */ + /* Check buffers are big enough and grow if needed. */ if ((ret = CheckAvailableSize(ssl, args->sendSz)) != 0) return ret; @@ -3300,6 +3389,12 @@ int SendTls13ClientHello(WOLFSSL* ssl) #endif /* WOLFSSL_TLS13_MIDDLEBOX_COMPAT */ } +#ifdef WOLFSSL_DTLS13 + /* legacy_cookie_id. always 0 length vector */ + if (ssl->options.dtls) + args->output[args->idx++] = 0; +#endif /* WOLFSSL_DTLS13 */ + /* Cipher suites */ c16toa(ssl->suites->suiteSz, args->output + args->idx); args->idx += OPAQUE16_LEN; @@ -3333,11 +3428,21 @@ int SendTls13ClientHello(WOLFSSL* ssl) /* Resumption has a specific set of extensions and binder is calculated * for each identity. */ - if (TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY)) + if (TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY)) { ret = WritePSKBinders(ssl, args->output, args->idx); + } else #endif - ret = HashOutput(ssl, args->output, args->idx, 0); + { +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) + ret = Dtls13HashHandshake(ssl, + args->output + Dtls13GetRlHeaderLength(0), + args->idx - Dtls13GetRlHeaderLength(0)); + else +#endif /* WOLFSSL_DTLS13 */ + ret = HashOutput(ssl, args->output, args->idx, 0); + } if (ret != 0) return ret; @@ -3351,6 +3456,17 @@ int SendTls13ClientHello(WOLFSSL* ssl) } #endif +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + ret = Dtls13HandshakeSend(ssl, args->output, args->sendSz, + args->idx, client_hello, 0); + + WOLFSSL_LEAVE("SendTls13ClientHello", ret); + WOLFSSL_END(WC_FUNC_CLIENT_HELLO_SEND); + return ret; + } +#endif /* WOLFSSL_DTLS13 */ + ssl->buffers.outputBuffer.length += args->sendSz; /* Advance state and proceed */ @@ -4431,6 +4547,16 @@ static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) return ret; +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + ret = Dtls13NewEpoch(ssl, + w64From32(0x0, DTLS13_EPOCH_EARLYDATA), + DECRYPT_SIDE_ONLY); + if (ret != 0) + return ret; + } +#endif /* WOLFSSL_DTLS13 */ + ssl->earlyData = process_early_data; } else @@ -4538,7 +4664,7 @@ static int CheckCookie(WOLFSSL* ssl, byte* cookie, byte cookieSz) #define HRR_BODY_SZ (VERSION_SZ + RAN_LEN + ENUM_LEN + ID_LEN + \ SUITE_LEN + COMP_LEN + OPAQUE16_LEN) /* HH | PV | CipherSuite | Ext Len | Key Share | Supported Version | Cookie */ -#define MAX_HRR_SZ (HANDSHAKE_HEADER_SZ + \ +#define MAX_HRR_SZ (HRR_MAX_HS_HEADER_SZ + \ HRR_BODY_SZ + \ HRR_KEY_SHARE_SZ + \ HRR_VERSIONS_SZ + \ @@ -4553,7 +4679,7 @@ static int CheckCookie(WOLFSSL* ssl, byte* cookie, byte cookieSz) */ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie) { - byte header[HANDSHAKE_HEADER_SZ] = {0}; + byte header[HRR_MAX_HS_HEADER_SZ] = {0}; byte hrr[MAX_HRR_SZ] = {0}; int hrrIdx; word32 idx; @@ -4573,6 +4699,7 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie) /* Restart handshake hash with synthetic message hash. */ AddTls13HandShakeHeader(header, hashSz, 0, 0, message_hash, ssl); + if ((ret = InitHandshakeHashes(ssl)) != 0) return ret; if ((ret = HashRaw(ssl, header, sizeof(header))) != 0) @@ -4595,9 +4722,14 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie) idx += hashSz; hrrIdx = HANDSHAKE_HEADER_SZ; +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) + hrrIdx += DTLS_HANDSHAKE_EXTRA; +#endif /* WOLFSSL_DTLS13 */ + /* The negotiated protocol version. */ hrr[hrrIdx++] = ssl->version.major; - hrr[hrrIdx++] = TLSv1_2_MINOR; + hrr[hrrIdx++] = ssl->options.dtls ? DTLSv1_2_MINOR : TLSv1_2_MINOR; /* HelloRetryRequest message has fixed value for random. */ XMEMCPY(hrr + hrrIdx, helloRetryRequestRandom, RAN_LEN); @@ -4657,8 +4789,19 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie) WOLFSSL_BUFFER(cookieData, cookie->len); #endif - if ((ret = HashRaw(ssl, hrr, hrrIdx)) != 0) +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + ret = Dtls13HashHandshake(ssl, hrr, hrrIdx); + } + else +#endif /* WOLFSSL_DTLS13 */ + { + ret = HashRaw(ssl, hrr, hrrIdx); + } + + if (ret != 0) return ret; + return HashRaw(ssl, cookieData, cookie->len); } #endif @@ -4688,6 +4831,16 @@ static int DoTls13SupportedVersions(WOLFSSL* ssl, const byte* input, word32 i, return BUFFER_ERROR; } i += b; +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + /* legacy_cookie - not used in DTLS v1.3 */ + b = input[i++]; + if (i + b > helloSz) { + return BUFFER_ERROR; + } + i += b; + } +#endif /* WOLFSSL_DTLS13 */ /* Cipher suites */ if (i + OPAQUE16_LEN > helloSz) return BUFFER_ERROR; @@ -4927,6 +5080,12 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, args->idx += ID_LEN; } +#ifdef WOLFSSL_DTLS13 + /* legacy_cookie */ + if (ssl->options.dtls) + args->idx += OPAQUE8_LEN; +#endif /* WOLFSSL_DTLS13 */ + args->clSuites = (Suites*)XMALLOC(sizeof(Suites), ssl->heap, DYNAMIC_TYPE_SUITES); if (args->clSuites == NULL) { @@ -5132,6 +5291,26 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, ret = INPUT_CASE_ERROR; } /* switch (ssl->options.asyncState) */ +#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE) + /* We are using DTLSv13 and set the HRR cookie secret, use the cookie to + perform a return-routability check. */ + if (ret == 0 && ssl->options.dtls && ssl->options.sendCookie && + ssl->options.serverState != SERVER_HELLO_RETRY_REQUEST_COMPLETE) { + + /* ssl->options.serverState != SERVER_HELLO_RETRY_REQUEST_COMPLETE + so the client already provided a good KeyShareEntry. In this case + we don't add the KEY_SHARE extension to the HelloRetryRequest or + in the Cookie. The RFC8446 forbids to select a supported group + with KeyShare extension in HelloRetryRequest if the client + already provided a KeyShareEntry for that group. See rfc8446 + section 4.1.4 */ + TLSX_Remove(&ssl->extensions, TLSX_KEY_SHARE, ssl->heap); + + /* send an HRR (see wolfSSL_Accept_TLSv13()) */ + ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE; + } +#endif /* WOLFSSL_DTLS13 */ + exit_dch: WOLFSSL_LEAVE("DoTls13ClientHello", ret); @@ -5176,6 +5355,11 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType) return ret; } +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) + idx = DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ; +#endif /* WOLFSSL_DTLS13 */ + /* Protocol version, server random, session id, cipher suite, compression * and extensions. */ @@ -5243,9 +5427,20 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType) if (ret != 0) return ret; - ssl->buffers.outputBuffer.length += sendSz; - if ((ret = HashOutput(ssl, output, sendSz, 0)) != 0) +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + ret = Dtls13HashHandshake(ssl, + output + Dtls13GetRlHeaderLength(0) , + sendSz - Dtls13GetRlHeaderLength(0)); + } + else +#endif /* WOLFSSL_DTLS13 */ + { + ret = HashOutput(ssl, output, sendSz, 0); + } + + if (ret != 0) return ret; #ifdef WOLFSSL_CALLBACKS @@ -5260,6 +5455,19 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType) if (extMsgType == server_hello) ssl->options.serverState = SERVER_HELLO_COMPLETE; +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + ret = Dtls13HandshakeSend(ssl, output, sendSz, sendSz, + server_hello, 0); + + WOLFSSL_LEAVE("SendTls13ServerHello", ret); + WOLFSSL_END(WC_FUNC_SERVER_HELLO_SEND); + return ret; + } +#endif /* WOLFSSL_DTLS13 */ + + ssl->buffers.outputBuffer.length += sendSz; + if (!ssl->options.groupMessages || extMsgType != server_hello) ret = SendBuffered(ssl); @@ -5283,7 +5491,7 @@ static int SendTls13EncryptedExtensions(WOLFSSL* ssl) int ret; byte* output; word16 length = 0; - word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + word32 idx; int sendSz; WOLFSSL_START(WC_FUNC_ENCRYPTED_EXTENSIONS_SEND); @@ -5291,6 +5499,16 @@ static int SendTls13EncryptedExtensions(WOLFSSL* ssl) ssl->keys.encryptionOn = 1; +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + idx = Dtls13GetHeadersLength(encrypted_extensions); + } + else +#endif /* WOLFSSL_DTLS13 */ + { + idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + } + #if defined(HAVE_SUPPORTED_CURVES) && !defined(WOLFSSL_NO_SERVER_GROUPS_EXT) if ((ret = TLSX_SupportedCurve_CheckPriority(ssl)) != 0) return ret; @@ -5318,6 +5536,24 @@ static int SendTls13EncryptedExtensions(WOLFSSL* ssl) return ret; #endif +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + w64wrapper epochHandshake = w64From32(0, DTLS13_EPOCH_HANDSHAKE); + ssl->dtls13Epoch = epochHandshake; + + ret = Dtls13NewEpoch( + ssl, epochHandshake, ENCRYPT_AND_DECRYPT_SIDE); + if (ret != 0) + return ret; + + ret = Dtls13SetEpochKeys( + ssl, epochHandshake, ENCRYPT_AND_DECRYPT_SIDE); + if (ret != 0) + return ret; + + } +#endif /* WOLFSSL_DTLS13 */ + ret = TLSX_GetResponseSize(ssl, encrypted_extensions, &length); if (ret != 0) return ret; @@ -5352,6 +5588,21 @@ static int SendTls13EncryptedExtensions(WOLFSSL* ssl) } #endif +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + ret = Dtls13HandshakeSend(ssl, output, sendSz, idx, + encrypted_extensions, 1); + + if (ret == 0) + ssl->options.serverState = SERVER_ENCRYPTED_EXTENSIONS_COMPLETE; + + WOLFSSL_LEAVE("SendTls13EncryptedExtensions", ret); + WOLFSSL_END(WC_FUNC_ENCRYPTED_EXTENSIONS_SEND); + + return ret; + } +#endif /* WOLFSSL_DTLS13 */ + /* This handshake message is always encrypted. */ sendSz = BuildTls13Message(ssl, output, sendSz, output + RECORD_HEADER_SZ, idx - RECORD_HEADER_SZ, handshake, 1, 0, 0); @@ -5365,6 +5616,7 @@ static int SendTls13EncryptedExtensions(WOLFSSL* ssl) if (!ssl->options.groupMessages) ret = SendBuffered(ssl); + WOLFSSL_LEAVE("SendTls13EncryptedExtensions", ret); WOLFSSL_END(WC_FUNC_ENCRYPTED_EXTENSIONS_SEND); @@ -5405,6 +5657,11 @@ static int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx, ext->resp = 0; i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) + i = Dtls13GetRlHeaderLength(1) + DTLS_HANDSHAKE_HEADER_SZ; +#endif /* WOLFSSL_DTLS13 */ + reqSz = (word16)(OPAQUE8_LEN + reqCtxLen); ret = TLSX_GetRequestSize(ssl, certificate_request, &reqSz); if (ret != 0) @@ -5439,6 +5696,19 @@ static int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx, return ret; i += reqSz; +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + ret = + Dtls13HandshakeSend(ssl, output, sendSz, i, certificate_request, 1); + + WOLFSSL_LEAVE("SendTls13CertificateRequest", ret); + WOLFSSL_END(WC_FUNC_CERTIFICATE_REQUEST_SEND); + + return ret; + + } +#endif /* WOLFSSL_DTLS13 */ + /* Always encrypted. */ sendSz = BuildTls13Message(ssl, output, sendSz, output + RECORD_HEADER_SZ, i - RECORD_HEADER_SZ, handshake, 1, 0, 0); @@ -6054,6 +6324,13 @@ static int SendTls13Certificate(WOLFSSL* ssl) word32 i = RECORD_HEADER_SZ; int sendSz = RECORD_HEADER_SZ; +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + i = Dtls13GetRlHeaderLength(1); + sendSz = (int)i; + } +#endif /* WOLFSSL_DTLS13 */ + ssl->options.buildingMsg = 1; if (ssl->fragOffset == 0) { @@ -6061,11 +6338,25 @@ static int SendTls13Certificate(WOLFSSL* ssl) maxFragment - HANDSHAKE_HEADER_SZ) { fragSz = headerSz + certSz + extSz + certChainSz; } - else +#ifdef WOLFSSL_DTLS13 + else if (ssl->options.dtls){ + /* short-circuit the fragmentation logic here. DTLS + fragmentation will be done in dtls13HandshakeSend() */ + fragSz = headerSz + certSz + extSz + certChainSz; + } +#endif /* WOLFSSL_DTLS13 */ + else { fragSz = maxFragment - HANDSHAKE_HEADER_SZ; + } sendSz += fragSz + HANDSHAKE_HEADER_SZ; i += HANDSHAKE_HEADER_SZ; +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + sendSz += DTLS_HANDSHAKE_EXTRA; + i += DTLS_HANDSHAKE_EXTRA; + } +#endif /* WOLFSSL_DTLS13 */ } else { fragSz = min(length, maxFragment); @@ -6154,25 +6445,35 @@ static int SendTls13Certificate(WOLFSSL* ssl) return BUFFER_E; } - /* This message is always encrypted. */ - sendSz = BuildTls13Message(ssl, output, sendSz, - output + RECORD_HEADER_SZ, - i - RECORD_HEADER_SZ, handshake, 1, 0, 0); - if (sendSz < 0) - return sendSz; +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + /* DTLS1.3 uses a separate variable and logic for fragments */ + ssl->fragOffset = 0; + ret = Dtls13HandshakeSend(ssl, output, sendSz, i, certificate, 1); + } + else +#endif /* WOLFSSL_DTLS13 */ + { + /* This message is always encrypted. */ + sendSz = BuildTls13Message(ssl, output, sendSz, + output + RECORD_HEADER_SZ, i - RECORD_HEADER_SZ, handshake, 1, + 0, 0); + if (sendSz < 0) + return sendSz; - #ifdef WOLFSSL_CALLBACKS +#ifdef WOLFSSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName(ssl, "Certificate"); if (ssl->toInfoOn) { AddPacketInfo(ssl, "Certificate", handshake, output, - sendSz, WRITE_PROTO, ssl->heap); + sendSz, WRITE_PROTO, ssl->heap); } - #endif +#endif - ssl->buffers.outputBuffer.length += sendSz; - if (!ssl->options.groupMessages) - ret = SendBuffered(ssl); + ssl->buffers.outputBuffer.length += sendSz; + if (!ssl->options.groupMessages) + ret = SendBuffered(ssl); + } } if (ret != WANT_WRITE) { @@ -6246,9 +6547,22 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) Scv13Args args[1]; #endif +#ifdef WOLFSSL_DTLS13 + int recordLayerHdrExtra; +#endif /* WOLFSSL_DTLS13 */ + WOLFSSL_START(WC_FUNC_CERTIFICATE_VERIFY_SEND); WOLFSSL_ENTER("SendTls13CertificateVerify"); +#ifdef WOLFSSL_DTLS13 + /* can be negative */ + if (ssl->options.dtls) + recordLayerHdrExtra = Dtls13GetRlHeaderLength(1) - RECORD_HEADER_SZ; + else + recordLayerHdrExtra = 0; + +#endif /* WOLFSSL_DTLS13 */ + #ifdef WOLFSSL_ASYNC_CRYPT if (ssl->async == NULL) { ssl->async = (struct WOLFSSL_ASYNC*) @@ -6314,6 +6628,14 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) args->verify = &args->output[RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ]; +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + rem -= recordLayerHdrExtra + DTLS_HANDSHAKE_EXTRA; + args->idx += recordLayerHdrExtra + DTLS_HANDSHAKE_EXTRA; + args->verify += recordLayerHdrExtra + DTLS_HANDSHAKE_EXTRA; + } +#endif /* WOLFSSL_DTLS13 */ + if (ssl->buffers.key == NULL) { #ifdef HAVE_PK_CALLBACKS if (wolfSSL_CTX_IsPrivatePkSet(ssl->ctx)) @@ -6572,7 +6894,11 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) args->sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + args->length + HASH_SIG_SIZE + VERIFY_HEADER; +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) + args->sendSz += recordLayerHdrExtra + DTLS_HANDSHAKE_EXTRA; +#endif /* WOLFSSL_DTLS13 */ /* Advance state and proceed */ ssl->options.asyncState = TLS_ASYNC_END; } /* case TLS_ASYNC_FINALIZE */ @@ -6580,6 +6906,18 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) case TLS_ASYNC_END: { +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + ret = Dtls13HandshakeSend(ssl, args->output, + MAX_CERT_VERIFY_SZ + MAX_MSG_EXTRA + MAX_MSG_EXTRA, + args->sendSz, certificate_verify, 1); + if (ret != 0) + goto exit_scv; + + break; + } +#endif /* WOLFSSL_DTLS13 */ + /* This message is always encrypted. */ ret = BuildTls13Message(ssl, args->output, MAX_CERT_VERIFY_SZ + MAX_MSG_EXTRA, @@ -7178,7 +7516,7 @@ int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #endif /* check against totalSz */ - if (*inOutIdx + size + ssl->keys.padSz > totalSz) + if (*inOutIdx + size > totalSz) return BUFFER_E; if (ssl->options.handShakeDone) { @@ -7269,6 +7607,14 @@ int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } #endif +#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_EARLY_DATA) + if (ssl->options.dtls && ssl->earlyData > early_data_ext) { + /* DTLSv1.3 has no EndOfearlydata messages. We stop processing EarlyData + as soon we receive the client's finished message */ + ssl->earlyData = done_early_data; + } +#endif /* WOLFSSL_DTLS13 && WOLFSSL_EARLY_DATA */ + WOLFSSL_LEAVE("DoTls13Finished", 0); WOLFSSL_END(WC_FUNC_FINISHED_DO); @@ -7292,9 +7638,22 @@ static int SendTls13Finished(WOLFSSL* ssl) int outputSz; byte* secret; +#ifdef WOLFSSL_DTLS13 + int dtlsRet = 0, isDtls = 0; +#endif /* WOLFSSL_DTLS13 */ + WOLFSSL_START(WC_FUNC_FINISHED_SEND); WOLFSSL_ENTER("SendTls13Finished"); +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + headerSz = DTLS_HANDSHAKE_HEADER_SZ; + /* using isDtls instead of ssl->options.dtls will abide clang static + analyzer on unsing an uninitialized value */ + isDtls = 1; + } +#endif /* WOLFSSL_DTLS13 */ + outputSz = WC_MAX_DIGEST_SIZE + DTLS_HANDSHAKE_HEADER_SZ + MAX_MSG_EXTRA; /* Check buffers are big enough and grow if needed. */ if ((ret = CheckAvailableSize(ssl, outputSz)) != 0) @@ -7305,6 +7664,11 @@ static int SendTls13Finished(WOLFSSL* ssl) ssl->buffers.outputBuffer.length; input = output + RECORD_HEADER_SZ; +#ifdef WOLFSSL_DTLS13 + if (isDtls) + input = output + Dtls13GetRlHeaderLength(1); +#endif /* WOLFSSL_DTLS13 */ + AddTls13HandShakeHeader(input, finishedSz, 0, finishedSz, finished, ssl); /* make finished hashes */ @@ -7347,6 +7711,17 @@ static int SendTls13Finished(WOLFSSL* ssl) ssl->serverFinished_len = finishedSz; } #endif /* WOLFSSL_HAVE_TLS_UNIQUE */ + +#ifdef WOLFSSL_DTLS13 + if (isDtls) { + dtlsRet = Dtls13HandshakeSend(ssl, output, outputSz, + Dtls13GetRlHeaderLength(1) + headerSz + finishedSz, finished, 1); + if (dtlsRet != 0 && dtlsRet != WANT_WRITE) + return ret; + + } else +#endif /* WOLFSSL_DTLS13 */ + { /* This message is always encrypted. */ sendSz = BuildTls13Message(ssl, output, outputSz, input, headerSz + finishedSz, handshake, 1, 0, 0); @@ -7362,20 +7737,32 @@ static int SendTls13Finished(WOLFSSL* ssl) #endif ssl->buffers.outputBuffer.length += sendSz; + } if (ssl->options.side == WOLFSSL_SERVER_END) { +#ifdef WOLFSSL_EARLY_DATA + byte storeTrafficDecKeys = ssl->earlyData == no_early_data; +#endif /* Can send application data now. */ if ((ret = DeriveMasterSecret(ssl)) != 0) return ret; /* Last use of preMasterSecret - zeroize as soon as possible. */ ForceZero(ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz); #ifdef WOLFSSL_EARLY_DATA + +#ifdef WOLFSSL_DTLS13 + /* DTLS13 dynamically change keys and it needs all + the keys in ssl->keys to save the keying material */ + if (isDtls) + storeTrafficDecKeys = 1; +#endif /* WOLFSSL_DTLS13 */ + if ((ret = DeriveTls13Keys(ssl, traffic_key, ENCRYPT_SIDE_ONLY, 1)) != 0) { return ret; } if ((ret = DeriveTls13Keys(ssl, traffic_key, DECRYPT_SIDE_ONLY, - ssl->earlyData == no_early_data)) != 0) { + storeTrafficDecKeys)) != 0) { return ret; } #else @@ -7386,6 +7773,26 @@ static int SendTls13Finished(WOLFSSL* ssl) #endif if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) return ret; + +#ifdef WOLFSSL_DTLS13 + if (isDtls) { + w64wrapper epochTraffic0; + epochTraffic0 = w64From32(0, DTLS13_EPOCH_TRAFFIC0); + ssl->dtls13Epoch = epochTraffic0; + ssl->dtls13PeerEpoch = epochTraffic0; + + ret = Dtls13NewEpoch( + ssl, epochTraffic0, ENCRYPT_AND_DECRYPT_SIDE); + if (ret != 0) + return ret; + + ret = Dtls13SetEpochKeys( + ssl, epochTraffic0, ENCRYPT_AND_DECRYPT_SIDE); + if (ret != 0) + return ret; + + } +#endif /* WOLFSSL_DTLS13 */ } if (ssl->options.side == WOLFSSL_CLIENT_END && @@ -7407,6 +7814,26 @@ static int SendTls13Finished(WOLFSSL* ssl) if (ret != 0) return ret; #endif + +#ifdef WOLFSSL_DTLS13 + if (isDtls) { + w64wrapper epochTraffic0; + epochTraffic0 = w64From32(0, DTLS13_EPOCH_TRAFFIC0); + ssl->dtls13Epoch = epochTraffic0; + ssl->dtls13PeerEpoch = epochTraffic0; + + ret = Dtls13NewEpoch( + ssl, epochTraffic0, ENCRYPT_AND_DECRYPT_SIDE); + if (ret != 0) + return ret; + + ret = Dtls13SetEpochKeys( + ssl, epochTraffic0, ENCRYPT_AND_DECRYPT_SIDE); + if (ret != 0) + return ret; + + } +#endif /* WOLFSSL_DTLS13 */ } #ifndef NO_WOLFSSL_CLIENT @@ -7422,6 +7849,15 @@ static int SendTls13Finished(WOLFSSL* ssl) } #endif +#ifdef WOLFSSL_DTLS13 + if (isDtls) { + WOLFSSL_LEAVE("SendTls13Finished", ret); + WOLFSSL_END(WC_FUNC_FINISHED_SEND); + + return dtlsRet; + } +#endif /* WOLFSSL_DTLS13 */ + if ((ret = SendBuffered(ssl)) != 0) return ret; @@ -7908,6 +8344,11 @@ static int SendTls13NewSessionTicket(WOLFSSL* ssl) WOLFSSL_START(WC_FUNC_NEW_SESSION_TICKET_SEND); WOLFSSL_ENTER("SendTls13NewSessionTicket"); +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) + idx = Dtls13GetRlHeaderLength(1) + DTLS_HANDSHAKE_HEADER_SZ; +#endif /* WOLFSSL_DTLS13 */ + #ifdef WOLFSSL_TLS13_TICKET_BEFORE_FINISHED if (!ssl->msgsReceived.got_finished) { if ((ret = ExpectedResumptionSecret(ssl)) != 0) @@ -7993,6 +8434,11 @@ static int SendTls13NewSessionTicket(WOLFSSL* ssl) AddSession(ssl); #endif +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) + return Dtls13HandshakeSend(ssl, output, sendSz, idx, session_ticket, 0); +#endif /* WOLFSSL_DTLS13 */ + /* This message is always encrypted. */ sendSz = BuildTls13Message(ssl, output, sendSz, output + RECORD_HEADER_SZ, idx - RECORD_HEADER_SZ, handshake, 0, 0, 0); @@ -8241,7 +8687,7 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) * Handshake Authentication). */ if (ssl->options.serverState != SERVER_ENCRYPTED_EXTENSIONS_COMPLETE && - (ssl->options.serverState != SERVER_FINISHED_COMPLETE || + (ssl->options.serverState < SERVER_FINISHED_COMPLETE || ssl->options.clientState != CLIENT_FINISHED_COMPLETE)) { WOLFSSL_MSG("CertificateRequest received out of order"); return OUT_OF_ORDER_E; @@ -8352,7 +8798,7 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) #ifndef NO_WOLFSSL_SERVER /* Check state on server. */ if (ssl->options.side == WOLFSSL_SERVER_END) { - if (ssl->options.serverState != SERVER_FINISHED_COMPLETE) { + if (ssl->options.serverState < SERVER_FINISHED_COMPLETE) { WOLFSSL_MSG("Finished received out of order - serverState"); return OUT_OF_ORDER_E; } @@ -8361,7 +8807,9 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) return OUT_OF_ORDER_E; } #ifdef WOLFSSL_EARLY_DATA - if (ssl->earlyData == process_early_data) { + if (ssl->earlyData == process_early_data && + /* early data may be lost when using DTLS */ + !ssl->options.dtls) { return OUT_OF_ORDER_E; } #endif @@ -8625,6 +9073,26 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, #endif if ((ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE)) != 0) return ret; + +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + w64wrapper epochHandshake; + epochHandshake = w64From32(0, DTLS13_EPOCH_HANDSHAKE); + ssl->dtls13Epoch = epochHandshake; + ssl->dtls13PeerEpoch = epochHandshake; + + ret = Dtls13NewEpoch( + ssl, epochHandshake, ENCRYPT_AND_DECRYPT_SIDE); + if (ret != 0) + return ret; + + ret = Dtls13SetEpochKeys( + ssl, epochHandshake, ENCRYPT_AND_DECRYPT_SIDE); + if (ret != 0) + return ret; + + } +#endif /* WOLFSSL_DTLS13 */ } if (type == finished) { @@ -8811,6 +9279,7 @@ int DoTls13HandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, */ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) { + int advanceState; int ret = 0; WOLFSSL_ENTER("wolfSSL_connect_TLSv13()"); @@ -8838,6 +9307,19 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) } #endif /* WOLFSSL_WOLFSENTRY_HOOKS */ + /* fragOffset is non-zero when sending fragments. On the last + * fragment, fragOffset is zero again, and the state can be + * advanced. Also, only advance from states in which we send data */ + advanceState = (ssl->options.connectState == CONNECT_BEGIN || + ssl->options.connectState == HELLO_AGAIN || + (ssl->options.connectState >= FIRST_REPLY_DONE && + ssl->options.connectState <= FIRST_REPLY_FOURTH)); + +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) + advanceState = advanceState && !ssl->dtls13SendingFragments; +#endif /* WOLFSSL_DTLS13 */ + if (ssl->buffers.outputBuffer.length > 0 #ifdef WOLFSSL_ASYNC_CRYPT /* do not send buffered or advance state if last error was an @@ -8845,16 +9327,9 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) && ssl->error != WC_PENDING_E #endif ) { - if ((ret = SendBuffered(ssl)) == 0) { - /* fragOffset is non-zero when sending fragments. On the last - * fragment, fragOffset is zero again, and the state can be - * advanced. */ + if ((ssl->error = SendBuffered(ssl)) == 0) { if (ssl->fragOffset == 0 && !ssl->options.buildingMsg) { - /* Only increment from states in which we send data */ - if (ssl->options.connectState == CONNECT_BEGIN || - ssl->options.connectState == HELLO_AGAIN || - (ssl->options.connectState >= FIRST_REPLY_DONE && - ssl->options.connectState <= FIRST_REPLY_FOURTH)) { + if (advanceState) { ssl->options.connectState++; WOLFSSL_MSG("connect state: " "Advanced from last buffered fragment send"); @@ -8882,6 +9357,18 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) return WOLFSSL_FATAL_ERROR; } +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls && ssl->dtls13SendingFragments) { + if ((ssl->error = Dtls13FragmentsContinue(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + + /* we sent all the fragments. Advance state. */ + ssl->options.connectState++; + } +#endif /* WOLFSSL_DTLS13 */ + switch (ssl->options.connectState) { case CONNECT_BEGIN: @@ -8896,14 +9383,16 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) #ifdef WOLFSSL_EARLY_DATA if (ssl->earlyData != no_early_data) { #if defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) - if ((ssl->error = SendChangeCipher(ssl)) != 0) { - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; + if (!ssl->options.dtls) { + if ((ssl->error = SendChangeCipher(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.sentChangeCipher = 1; } - ssl->options.sentChangeCipher = 1; #endif - ssl->options.handShakeState = CLIENT_HELLO_COMPLETE; - return WOLFSSL_SUCCESS; + ssl->options.handShakeState = CLIENT_HELLO_COMPLETE; + return WOLFSSL_SUCCESS; } #endif FALL_THROUGH; @@ -8938,7 +9427,7 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST_COMPLETE) { #if defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) - if (!ssl->options.sentChangeCipher) { + if (!ssl->options.dtls && !ssl->options.sentChangeCipher) { if ((ssl->error = SendChangeCipher(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; @@ -8972,7 +9461,7 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) case FIRST_REPLY_DONE: #ifdef WOLFSSL_EARLY_DATA - if (ssl->earlyData != no_early_data) { + if (!ssl->options.dtls && ssl->earlyData != no_early_data) { if ((ssl->error = SendTls13EndOfEarlyData(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; @@ -8987,7 +9476,7 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) case FIRST_REPLY_FIRST: #if defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) - if (!ssl->options.sentChangeCipher) { + if (!ssl->options.sentChangeCipher && !ssl->options.dtls) { if ((ssl->error = SendChangeCipher(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; @@ -9745,9 +10234,12 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) #if !defined(NO_CERTS) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) word16 havePSK = 0; #endif + int advanceState; int ret = 0; + WOLFSSL_ENTER("SSL_accept_TLSv13()"); + #ifdef HAVE_ERRNO_H errno = 0; #endif @@ -9828,23 +10320,33 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) && ssl->error != WC_PENDING_E #endif ) { - if ((ret = SendBuffered(ssl)) == 0) { - /* fragOffset is non-zero when sending fragments. On the last - * fragment, fragOffset is zero again, and the state can be - * advanced. */ + + /* fragOffset is non-zero when sending fragments. On the last + * fragment, fragOffset is zero again, and the state can be + * advanced. */ + advanceState = + (ssl->options.acceptState == TLS13_ACCEPT_CLIENT_HELLO_DONE || + ssl->options.acceptState == + TLS13_ACCEPT_HELLO_RETRY_REQUEST_DONE || + ssl->options.acceptState == TLS13_ACCEPT_SECOND_REPLY_DONE || + ssl->options.acceptState == TLS13_SERVER_HELLO_SENT || + ssl->options.acceptState == TLS13_ACCEPT_THIRD_REPLY_DONE || + ssl->options.acceptState == TLS13_SERVER_EXTENSIONS_SENT || + ssl->options.acceptState == TLS13_CERT_REQ_SENT || + ssl->options.acceptState == TLS13_CERT_SENT || + ssl->options.acceptState == TLS13_CERT_VERIFY_SENT || + ssl->options.acceptState == TLS13_ACCEPT_FINISHED_SENT || + ssl->options.acceptState == TLS13_ACCEPT_FINISHED_DONE); + +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) + advanceState = advanceState && + !ssl->dtls13SendingFragments; +#endif /* WOLFSSL_DTLS13 */ + + if ((ssl->error = SendBuffered(ssl)) == 0) { if (ssl->fragOffset == 0 && !ssl->options.buildingMsg) { - /* Only increment from states in which we send data */ - if (ssl->options.acceptState == TLS13_ACCEPT_CLIENT_HELLO_DONE || - ssl->options.acceptState == TLS13_ACCEPT_HELLO_RETRY_REQUEST_DONE || - ssl->options.acceptState == TLS13_ACCEPT_SECOND_REPLY_DONE || - ssl->options.acceptState == TLS13_SERVER_HELLO_SENT || - ssl->options.acceptState == TLS13_ACCEPT_THIRD_REPLY_DONE || - ssl->options.acceptState == TLS13_SERVER_EXTENSIONS_SENT || - ssl->options.acceptState == TLS13_CERT_REQ_SENT || - ssl->options.acceptState == TLS13_CERT_SENT || - ssl->options.acceptState == TLS13_CERT_VERIFY_SENT || - ssl->options.acceptState == TLS13_ACCEPT_FINISHED_SENT || - ssl->options.acceptState == TLS13_ACCEPT_FINISHED_DONE) { + if (advanceState) { ssl->options.acceptState++; WOLFSSL_MSG("accept state: " "Advanced from last buffered fragment send"); @@ -9871,6 +10373,17 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls && ssl->dtls13SendingFragments) { + if ((ssl->error = Dtls13FragmentsContinue(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + + /* we sent all the fragments. Advance state. */ + ssl->options.acceptState++; + } +#endif /* WOLFSSL_DTLS13 */ switch (ssl->options.acceptState) { @@ -9908,7 +10421,7 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) case TLS13_ACCEPT_HELLO_RETRY_REQUEST_DONE : #ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT - if (ssl->options.serverState == + if (!ssl->options.dtls && ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST_COMPLETE) { if ((ssl->error = SendChangeCipher(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); @@ -9949,7 +10462,8 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) case TLS13_SERVER_HELLO_SENT : #if defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT) - if (!ssl->options.sentChangeCipher) { + if (!ssl->options.dtls + && !ssl->options.sentChangeCipher && !ssl->options.dtls) { if ((ssl->error = SendChangeCipher(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 9b238babc..1da42bae0 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1294,6 +1294,8 @@ enum Misc { DTLS_HANDSHAKE_HEADER_SZ = 12, /* normal + seq(2) + offset(3) + length(3) */ DTLS_RECORD_HEADER_SZ = 13, /* normal + epoch(2) + seq_num(6) */ + DTLS_UNIFIED_HEADER_MIN_SZ = 2, + DTLS_RECORD_HEADER_MAX_SZ = 13, DTLS_HANDSHAKE_EXTRA = 8, /* diff from normal */ DTLS_RECORD_EXTRA = 8, /* diff from normal */ DTLS_HANDSHAKE_SEQ_SZ = 2, /* handshake header sequence number */ @@ -2256,6 +2258,12 @@ typedef struct Keys { word16 curEpoch; /* Received epoch in current record */ word16 curSeq_hi; /* Received sequence in current record */ word32 curSeq_lo; + +#ifdef WOLFSSL_DTLS13 + w64wrapper curEpoch64; /* Received epoch in current record */ + w64wrapper curSeq; +#endif /* WOLFSSL_DTLS13 */ + #ifdef WOLFSSL_MULTICAST byte curPeerId; /* Received peer group ID in current record */ #endif @@ -4319,6 +4327,15 @@ typedef enum EarlyDataState { #ifdef WOLFSSL_DTLS13 +typedef struct Dtls13UnifiedHdrInfo { + word16 recordLength; + word16 headerLength; + byte seqLo; + byte seqHi; + byte seqHiPresent:1; + byte epochBits; +} Dtls13UnifiedHdrInfo; + enum { DTLS13_EPOCH_EARLYDATA = 1, DTLS13_EPOCH_HANDSHAKE = 2, @@ -4557,8 +4574,15 @@ struct WOLFSSL { w64wrapper dtls13Epoch; w64wrapper dtls13PeerEpoch; -#endif /* WOLFSSL_DTLS13 */ + word16 dtls13CurRlLength; + /* used to store the message if it needs to be fragmented */ + buffer dtls13FragmentsBuffer; + byte dtls13SendingFragments:1; + word32 dtls13MessageLength; + word32 dtls13FragOffset; + byte dtls13FragHandshakeType; +#endif /* WOLFSSL_DTLS13 */ #endif /* WOLFSSL_DTLS */ #ifdef WOLFSSL_CALLBACKS TimeoutInfo timeoutInfo; /* info saved during handshake */ @@ -4842,7 +4866,10 @@ enum ContentType { change_cipher_spec = 20, alert = 21, handshake = 22, - application_data = 23 + application_data = 23, +#ifdef WOLFSSL_DTLS13 + ack = 26, +#endif /* WOLFSSL_DTLS13 */ }; @@ -5309,11 +5336,44 @@ WOLFSSL_LOCAL int Dtls13NewEpoch(WOLFSSL* ssl, w64wrapper epochNumber, int side); WOLFSSL_LOCAL int Dtls13SetEpochKeys(WOLFSSL* ssl, w64wrapper epochNumber, enum encrypt_side side); +WOLFSSL_LOCAL int Dtls13GetSeq(WOLFSSL* ssl, int order, word32* seq, + byte increment); WOLFSSL_LOCAL int Dtls13DeriveSnKeys(WOLFSSL* ssl, int provision); WOLFSSL_LOCAL int Dtls13SetRecordNumberKeys(WOLFSSL* ssl, enum encrypt_side side); +WOLFSSL_LOCAL int Dtls13AddHeaders(byte* output, word32 length, + enum HandShakeType hs_type, WOLFSSL* ssl); +WOLFSSL_LOCAL word16 Dtls13GetHeadersLength(enum HandShakeType type); +WOLFSSL_LOCAL word16 Dtls13GetRlHeaderLength(byte is_encrypted); +WOLFSSL_LOCAL int Dtls13RlAddCiphertextHeader(WOLFSSL* ssl, byte* out, + word16 length); +WOLFSSL_LOCAL int Dtls13RlAddPlaintextHeader(WOLFSSL* ssl, byte* out, + enum ContentType content_type, word16 length); +WOLFSSL_LOCAL int Dtls13EncryptRecordNumber(WOLFSSL* ssl, byte* hdr, + word16 recordLength); +WOLFSSL_LOCAL int Dtls13IsUnifiedHeader(byte header_flags); +WOLFSSL_LOCAL int Dtls13ParseUnifiedRecordLayer(WOLFSSL* ssl, const byte* input, + word16 input_size, Dtls13UnifiedHdrInfo* hdrInfo); +WOLFSSL_LOCAL int Dtls13HandshakeSend(WOLFSSL* ssl, byte* output, + word16 output_size, word16 length, enum HandShakeType handshake_type, + int hash_output); +WOLFSSL_LOCAL int Dtls13RecordRecvd(WOLFSSL* ssl); +WOLFSSL_LOCAL int Dtls13HandshakeRecv(WOLFSSL* ssl, byte* input, + word32* inOutIdx, word32 totalSz); +WOLFSSL_LOCAL int Dtls13HandshakeAddHeader(WOLFSSL* ssl, byte* output, + enum HandShakeType msg_type, word32 length); +#define EE_MASK (0x3) +WOLFSSL_LOCAL int Dtls13FragmentsContinue(WOLFSSL* ssl); + +WOLFSSL_LOCAL int Dtls13ReconstructEpochNumber(WOLFSSL* ssl, byte epochBits, + w64wrapper* epoch); +WOLFSSL_LOCAL int Dtls13ReconstructSeqNumber(WOLFSSL* ssl, + Dtls13UnifiedHdrInfo* hdrInfo, w64wrapper* out); +WOLFSSL_LOCAL int Dtls13HashHandshake(WOLFSSL* ssl, const byte* output, + word16 length); #endif /* WOLFSSL_DTLS13 */ + #ifdef WOLFSSL_STATIC_EPHEMERAL WOLFSSL_LOCAL int wolfSSL_StaticEphemeralKeyLoad(WOLFSSL* ssl, int keyAlgo, void* keyPtr); #endif