Skip to content

Commit

Permalink
Adds DTLS 1.3 ACK message functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
fwh-dc committed Jul 24, 2024
1 parent d85ea40 commit bc9d50a
Show file tree
Hide file tree
Showing 24 changed files with 944 additions and 101 deletions.
4 changes: 4 additions & 0 deletions apps/lib/s_cb.c
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,10 @@ void msg_cb(int write_p, int version, int content_type, const void *buf,
/* type 23 */
str_content_type = ", ApplicationData";
break;
case SSL3_RT_ACK:
/* type 26 */
str_content_type = ", ACK";
break;
case SSL3_RT_HEADER:
/* type 256 */
str_content_type = ", RecordHeader";
Expand Down
2 changes: 2 additions & 0 deletions include/internal/statem.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ struct ossl_statem_st {
OSSL_HANDSHAKE_STATE hand_state;
/* The handshake state requested by an API call (e.g. HelloRequest) */
OSSL_HANDSHAKE_STATE request_state;
/* The handshake state waiting for acknowledge */
OSSL_HANDSHAKE_STATE defered_ack_state;
int in_init;
int read_state_first_init;
/* true when we are actually in SSL_accept() or SSL_connect() */
Expand Down
6 changes: 5 additions & 1 deletion include/openssl/ssl.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -1063,7 +1063,11 @@ typedef enum {
TLS_ST_EARLY_DATA,
TLS_ST_PENDING_EARLY_DATA_END,
TLS_ST_CW_END_OF_EARLY_DATA,
TLS_ST_SR_END_OF_EARLY_DATA
TLS_ST_SR_END_OF_EARLY_DATA,
TLS_ST_CR_ACK,
TLS_ST_CW_ACK,
TLS_ST_SR_ACK,
TLS_ST_SW_ACK
} OSSL_HANDSHAKE_STATE;

/*
Expand Down
4 changes: 4 additions & 0 deletions include/openssl/ssl3.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ extern "C" {
# define SSL3_RT_ALERT 21
# define SSL3_RT_HANDSHAKE 22
# define SSL3_RT_APPLICATION_DATA 23
# define SSL3_RT_ACK 26 /*RFC 9147*/

/* Pseudo content types to indicate additional parameters */
# define TLS1_RT_CRYPTO 0x1000
Expand Down Expand Up @@ -333,6 +334,9 @@ extern "C" {
# define SSL3_MT_MESSAGE_HASH 254
# define DTLS1_MT_HELLO_VERIFY_REQUEST 3

/* Dummy message type for handling ACK like a normal handshake message */
# define DTLS13_MT_ACK 0x0126

/* Dummy message type for handling CCS like a normal handshake message */
# define SSL3_MT_CHANGE_CIPHER_SPEC 0x0101

Expand Down
263 changes: 263 additions & 0 deletions include/openssl/x509_acert.h

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions ssl/d1_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,15 @@ void dtls1_clear_received_buffer(SSL_CONNECTION *s)
}
}

void dtls1_remove_sent_buffer_item(struct pqueue_st *pq, unsigned char *prio64be) {
pitem *item = NULL;

while ((item = pqueue_pop_item(pq, prio64be)) != NULL) {
dtls1_sent_msg_free((dtls_sent_msg *)item->data);
pitem_free(item);
}
}

void dtls1_clear_sent_buffer(SSL_CONNECTION *s)
{
pitem *item = NULL;
Expand Down
35 changes: 25 additions & 10 deletions ssl/pqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,31 +96,46 @@ pitem *pqueue_pop(pqueue *pq)
return item;
}

pitem *pqueue_find(pqueue *pq, unsigned char *prio64be)
static pitem *pqueue_find_and_pop(pqueue *pq, unsigned char *prio64be, int pop)
{
pitem *next;
pitem *curr;
pitem *prev = NULL;
pitem *found = NULL;

if (pq->items == NULL)
return NULL;

for (next = pq->items; next->next != NULL; next = next->next) {
if (memcmp(next->priority, prio64be, 8) == 0) {
found = next;
for (curr = pq->items; curr->next != NULL; curr = curr->next) {
if (memcmp(curr->priority, prio64be, 8) == 0) {
found = curr;
break;
}
prev = curr;
}

/* check the one last node */
if (memcmp(next->priority, prio64be, 8) == 0)
found = next;

if (!found)
return NULL;
if (found == NULL && memcmp(curr->priority, prio64be, 8) == 0)
found = curr;

if (found != NULL && pop) {
if (prev == NULL)
pq->items = found->next;
else
prev->next = found->next;
}

return found;
}

pitem *pqueue_find(pqueue *pq, unsigned char *prio64be) {
return pqueue_find_and_pop(pq, prio64be, 0);
}

pitem *pqueue_pop_item(pqueue *pq, unsigned char *prio64be)
{
return pqueue_find_and_pop(pq, prio64be, 1);
}

pitem *pqueue_iterator(pqueue *pq)
{
return pqueue_peek(pq);
Expand Down
3 changes: 2 additions & 1 deletion ssl/record/methods/tls_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -1086,7 +1086,8 @@ int tls13_common_post_process_record(OSSL_RECORD_LAYER *rl, TLS_RL_RECORD *rec)
{
if (rec->type != SSL3_RT_APPLICATION_DATA
&& rec->type != SSL3_RT_ALERT
&& rec->type != SSL3_RT_HANDSHAKE) {
&& rec->type != SSL3_RT_HANDSHAKE
&& rec->type != SSL3_RT_ACK) {
RLAYERfatal(rl, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_BAD_RECORD_TYPE);
return 0;
}
Expand Down
20 changes: 12 additions & 8 deletions ssl/record/rec_layer_d1.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,13 +314,14 @@ int dtls1_read_bytes(SSL *s, uint8_t type, uint8_t *recvd_type,
}

if (type == rr->type
|| (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC
&& type == SSL3_RT_HANDSHAKE && recvd_type != NULL
&& !is_dtls13)) {
|| (type == SSL3_RT_HANDSHAKE
&& ((!is_dtls13 && recvd_type != NULL && rr->type == SSL3_RT_CHANGE_CIPHER_SPEC)
|| (is_dtls13 && rr->type == SSL3_RT_ACK)))) {
/*
* SSL3_RT_APPLICATION_DATA or
* SSL3_RT_HANDSHAKE or
* SSL3_RT_CHANGE_CIPHER_SPEC
* SSL3_RT_CHANGE_CIPHER_SPEC or
* SSL3_RT_ACK
*/
/*
* make sure that we are not getting application data when we are
Expand Down Expand Up @@ -489,15 +490,17 @@ int dtls1_read_bytes(SSL *s, uint8_t type, uint8_t *recvd_type,
/*
* Unexpected handshake message (Client Hello, or protocol violation)
*/
if (rr->type == SSL3_RT_HANDSHAKE && !ossl_statem_get_in_handshake(sc)) {
if (!ossl_statem_get_in_handshake(sc)
&& (rr->type == SSL3_RT_HANDSHAKE || rr->type == SSL3_RT_ACK)) {
unsigned char msg_type;

/*
* This may just be a stale retransmit. Also sanity check that we have
* at least enough record bytes for a message header
*/
if (rr->epoch != sc->rlayer.d->r_epoch
|| rr->length < DTLS1_HM_HEADER_LENGTH) {
if (rr->type == SSL3_RT_HANDSHAKE
&& (rr->epoch != sc->rlayer.d->r_epoch
|| rr->length < DTLS1_HM_HEADER_LENGTH)) {
if (!ssl_release_record(sc, rr, 0))
return -1;
goto start;
Expand All @@ -509,7 +512,7 @@ int dtls1_read_bytes(SSL *s, uint8_t type, uint8_t *recvd_type,
* If we are server, we may have a repeated FINISHED of the client
* here, then retransmit our CCS and FINISHED.
*/
if (msg_type == SSL3_MT_FINISHED) {
if (rr->type == SSL3_RT_HANDSHAKE && msg_type == SSL3_MT_FINISHED) {
if (dtls1_check_timeout_num(sc) < 0) {
/* SSLfatal) already called */
return -1;
Expand Down Expand Up @@ -585,6 +588,7 @@ int dtls1_read_bytes(SSL *s, uint8_t type, uint8_t *recvd_type,
case SSL3_RT_CHANGE_CIPHER_SPEC:
case SSL3_RT_ALERT:
case SSL3_RT_HANDSHAKE:
case SSL3_RT_ACK:
/*
* we already handled all of these, with the possible exception of
* SSL3_RT_HANDSHAKE when ossl_statem_get_in_handshake(s) is true, but
Expand Down
21 changes: 19 additions & 2 deletions ssl/ssl_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -1961,12 +1961,14 @@ void pqueue_free(pqueue *pq);
pitem *pqueue_insert(pqueue *pq, pitem *item);
pitem *pqueue_peek(pqueue *pq);
pitem *pqueue_pop(pqueue *pq);
pitem *pqueue_pop_item(pqueue *pq, unsigned char *prio64be);
pitem *pqueue_find(pqueue *pq, unsigned char *prio64be);
pitem *pqueue_iterator(pqueue *pq);
pitem *pqueue_next(piterator *iter);
size_t pqueue_size(pqueue *pq);

typedef struct dtls_msg_info_st {
unsigned char record_type;
unsigned char msg_type;
size_t msg_body_len;
unsigned short msg_seq;
Expand All @@ -1979,6 +1981,14 @@ typedef struct dtls_sent_msg_st {
struct dtls1_retransmit_state saved_retransmit_state;
} dtls_sent_msg;

#define DTLS_ACK_REC_NUM_LEN 32

/* rfc9147, section 4 */
typedef struct dtls1_record_number_st {
uint64_t epoch;
uint64_t sequence_number;
} DTLS1_RECORD_NUMBER;

typedef struct dtls1_state_st {
unsigned char cookie[DTLS1_COOKIE_LENGTH];
size_t cookie_len;
Expand Down Expand Up @@ -2011,6 +2021,10 @@ typedef struct dtls1_state_st {
int shutdown_received;
# endif

/* Sequence numbers that are to be acknowledged */
DTLS1_RECORD_NUMBER ack_rec_num[DTLS_ACK_REC_NUM_LEN];
size_t ack_rec_num_count;

DTLS_timer_cb timer_cb;

} DTLS1_STATE;
Expand Down Expand Up @@ -2716,11 +2730,14 @@ int dtls1_write_app_data_bytes(SSL *s, uint8_t type, const void *buf_,
__owur int dtls1_read_failed(SSL_CONNECTION *s, int code);
__owur int dtls1_buffer_sent_message(SSL_CONNECTION *s, int record_type);
__owur int dtls1_retransmit_message(SSL_CONNECTION *s, unsigned short seq,
int *found);
__owur int dtls1_get_queue_priority(unsigned short seq, int is_ccs);
int record_type, int *found);
void dtls1_get_queue_priority(unsigned char *prio64be, unsigned short seq,
int record_type);
int dtls1_retransmit_sent_messages(SSL_CONNECTION *s);
void dtls1_clear_received_buffer(SSL_CONNECTION *s);
void dtls1_clear_sent_buffer(SSL_CONNECTION *s);
void dtls1_remove_sent_buffer_item(struct pqueue_st *pq,
unsigned char *prio64be);
__owur OSSL_TIME dtls1_default_timeout(void);
__owur int dtls1_get_timeout(const SSL_CONNECTION *s, OSSL_TIME *timeleft);
__owur int dtls1_check_timeout_num(SSL_CONNECTION *s);
Expand Down
16 changes: 16 additions & 0 deletions ssl/ssl_stat.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,14 @@ const char *SSL_state_string_long(const SSL *s)
return "TLSv1.3 write end of early data";
case TLS_ST_SR_END_OF_EARLY_DATA:
return "TLSv1.3 read end of early data";
case TLS_ST_CR_ACK:
return "DTLSv1.3 read server ack";
case TLS_ST_CW_ACK:
return "DTLSv1.3 write client ack";
case TLS_ST_SR_ACK:
return "DTLSv1.3 read client ack";
case TLS_ST_SW_ACK:
return "DTLSv1.3 write server ack";
default:
return "unknown state";
}
Expand Down Expand Up @@ -240,6 +248,14 @@ const char *SSL_state_string(const SSL *s)
return "TWEOED";
case TLS_ST_SR_END_OF_EARLY_DATA:
return "TWEOED";
case TLS_ST_CR_ACK:
return "TRCACK";
case TLS_ST_CW_ACK:
return "TWCACK";
case TLS_ST_SR_ACK:
return "TRSACK";
case TLS_ST_SW_ACK:
return "TWSACK";
default:
return "UNKWN";
}
Expand Down
23 changes: 15 additions & 8 deletions ssl/statem/statem.c
Original file line number Diff line number Diff line change
Expand Up @@ -744,17 +744,22 @@ static SUB_STATE_RETURN read_state_machine(SSL_CONNECTION *s)
*/
static int statem_do_write(SSL_CONNECTION *s)
{
int record_type;
OSSL_STATEM *st = &s->statem;

if (st->hand_state == TLS_ST_CW_CHANGE
|| st->hand_state == TLS_ST_SW_CHANGE) {
if (SSL_CONNECTION_IS_DTLS(s))
return dtls1_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC);
else
return ssl3_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC);
} else {
|| st->hand_state == TLS_ST_SW_CHANGE)
record_type = SSL3_RT_CHANGE_CIPHER_SPEC;
else if (st->hand_state == TLS_ST_CW_ACK
|| st->hand_state == TLS_ST_SW_ACK)
record_type = SSL3_RT_ACK;
else
return ssl_do_write(s);
}

if (SSL_CONNECTION_IS_DTLS(s))
return dtls1_do_write(s, record_type);
else
return ssl3_do_write(s, record_type);
}

/*
Expand Down Expand Up @@ -917,7 +922,9 @@ static SUB_STATE_RETURN write_state_machine(SSL_CONNECTION *s)
/* Fall through */

case WRITE_STATE_SEND:
if (SSL_CONNECTION_IS_DTLS(s) && st->use_timer) {
if (SSL_CONNECTION_IS_DTLS(s) && st->use_timer
&& st->hand_state != TLS_ST_CW_ACK
&& st->hand_state != TLS_ST_SW_ACK) {
dtls1_start_timer(s);
}
ret = statem_do_write(s);
Expand Down
Loading

0 comments on commit bc9d50a

Please sign in to comment.