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 Mar 14, 2024
1 parent ac6b240 commit 648027f
Show file tree
Hide file tree
Showing 15 changed files with 385 additions and 78 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 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 @@ -1066,7 +1066,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
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_hm_fragment_free((hm_fragment *)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 @@ -1071,7 +1071,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
10 changes: 6 additions & 4 deletions ssl/record/rec_layer_d1.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,13 +314,15 @@ 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)) {
|| (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC
&& type == SSL3_RT_HANDSHAKE && recvd_type != NULL
&& !is_dtls13)
|| (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
20 changes: 18 additions & 2 deletions ssl/ssl_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -1923,11 +1923,20 @@ 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);

#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 @@ -1958,6 +1967,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 @@ -2666,11 +2679,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_message(SSL_CONNECTION *s, int ccs);
__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 is_ccs, int *found);
__owur void dtls1_get_queue_priority(unsigned char *prio64be,
unsigned short seq, int is_ccs);
int dtls1_retransmit_buffered_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);
void dtls1_get_message_header(const unsigned char *data,
struct hm_header_st *msg_hdr);
__owur OSSL_TIME dtls1_default_timeout(void);
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
47 changes: 46 additions & 1 deletion ssl/statem/statem_clnt.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,13 @@ static int ossl_statem_client13_read_transition(SSL_CONNECTION *s, int mt)
}
break;

case TLS_ST_CW_KEY_UPDATE:
case TLS_ST_CW_FINISHED:
if (mt == DTLS13_MT_ACK) {
st->hand_state = TLS_ST_CR_ACK;
return 1;
}

case TLS_ST_OK:
if (mt == SSL3_MT_NEWSESSION_TICKET) {
st->hand_state = TLS_ST_CR_SESSION_TICKET;
Expand Down Expand Up @@ -506,9 +513,31 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL_CONNECTION *s)
return WRITE_TRAN_CONTINUE;

case TLS_ST_CR_KEY_UPDATE:
case TLS_ST_CW_KEY_UPDATE:
if (SSL_CONNECTION_IS_DTLS13(s)) {
st->hand_state = TLS_ST_CW_ACK;
return WRITE_TRAN_CONTINUE;
}
/* Fall-through */
case TLS_ST_CR_SESSION_TICKET:
if (SSL_CONNECTION_IS_DTLS13(s)) {
st->hand_state = TLS_ST_CW_ACK;
return WRITE_TRAN_CONTINUE;
}
/* Fall-through */
case TLS_ST_CW_KEY_UPDATE:
case TLS_ST_CW_FINISHED:
if (SSL_CONNECTION_IS_DTLS13(s))
/* We wait for ACK */
return WRITE_TRAN_FINISHED;
else
st->hand_state = TLS_ST_OK;
return WRITE_TRAN_CONTINUE;

case TLS_ST_CR_ACK:
st->hand_state = TLS_ST_OK;
return WRITE_TRAN_CONTINUE;

case TLS_ST_CW_ACK:
st->hand_state = TLS_ST_OK;
return WRITE_TRAN_CONTINUE;

Expand Down Expand Up @@ -909,6 +938,11 @@ WORK_STATE ossl_statem_client_post_work(SSL_CONNECTION *s, WORK_STATE wst)
return WORK_ERROR;
}
break;

case TLS_ST_CW_ACK:
if (statem_flush(s) != 1)
return WORK_MORE_A;
break;
}

return WORK_FINISHED_CONTINUE;
Expand Down Expand Up @@ -993,6 +1027,11 @@ int ossl_statem_client_construct_message(SSL_CONNECTION *s,
*confunc = tls_construct_key_update;
*mt = SSL3_MT_KEY_UPDATE;
break;

case TLS_ST_CW_ACK:
*confunc = dtls_construct_ack;
*mt = DTLS13_MT_ACK;
break;
}

return 1;
Expand Down Expand Up @@ -1058,6 +1097,9 @@ size_t ossl_statem_client_max_message_size(SSL_CONNECTION *s)

case TLS_ST_CR_KEY_UPDATE:
return KEY_UPDATE_MAX_LENGTH;

case TLS_ST_CR_ACK:
return 2 + (0x1 << 16) - 1;
}
}

Expand Down Expand Up @@ -1121,6 +1163,9 @@ MSG_PROCESS_RETURN ossl_statem_client_process_message(SSL_CONNECTION *s,

case TLS_ST_CR_KEY_UPDATE:
return tls_process_key_update(s, pkt);

case TLS_ST_CR_ACK:
return dtls_process_ack(s, pkt);
}
}

Expand Down
Loading

0 comments on commit 648027f

Please sign in to comment.