summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjsing <>2021-08-31 13:34:55 +0000
committerjsing <>2021-08-31 13:34:55 +0000
commitf55a628b1a5faa0be72079bd24a247266121aa8b (patch)
treebc775bda4a2e85eae7ab9c598739564c29bfa447
parente6a921b7782b387c57ef5fd5205ee66276665998 (diff)
downloadopenbsd-f55a628b1a5faa0be72079bd24a247266121aa8b.tar.gz
openbsd-f55a628b1a5faa0be72079bd24a247266121aa8b.tar.bz2
openbsd-f55a628b1a5faa0be72079bd24a247266121aa8b.zip
Defragment DTLS.
In normal TLS, it is possible for record fragments to be sent that contain one byte of alert or handshake message payload. In this case we have to read and collate multiple message fragments before we can decide what to do with the record. However, in the case of DTLS, one record is effectively one packet and while it is possible to send handshake messages across multiple records/packets, the minimum payload is the DTLS handshake message header (plus one byte of data if the handshake message has a payload) - without this, there is insufficient information available to be able to reassemble the handshake message. Likewise, splitting an alert across multiple DTLS records simply does not work, as we have no way of knowing if we're collating the same alert or two different alerts that we lost half of each from (unfortunately, these details are not really specified in the DTLS RFC). This means that for DTLS we can expect to receive a full alert message (a whole two bytes) or a handshake record with at least the handshake message header (12 bytes). If we receive messages with less than these lengths we discard them and carry on (which is what the DTLS code already does). Remove all of the pointless fragment handling code from DTLS, while also fixing an issue where one case used rr->data instead of the handshake fragment. ok inoguchi@ tb@
-rw-r--r--src/lib/libssl/d1_pkt.c162
-rw-r--r--src/lib/libssl/dtls_locl.h9
2 files changed, 48 insertions, 123 deletions
diff --git a/src/lib/libssl/d1_pkt.c b/src/lib/libssl/d1_pkt.c
index 0b66bf7cc8..22f0167c75 100644
--- a/src/lib/libssl/d1_pkt.c
+++ b/src/lib/libssl/d1_pkt.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: d1_pkt.c,v 1.108 2021/08/31 13:14:43 jsing Exp $ */ 1/* $OpenBSD: d1_pkt.c,v 1.109 2021/08/31 13:34:55 jsing Exp $ */
2/* 2/*
3 * DTLS implementation written by Nagendra Modadugu 3 * DTLS implementation written by Nagendra Modadugu
4 * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. 4 * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
@@ -178,8 +178,6 @@ satsub64be(const unsigned char *v1, const unsigned char *v2)
178 return brw + (ret & 0xFF); 178 return brw + (ret & 0xFF);
179} 179}
180 180
181static int have_handshake_fragment(SSL *s, int type, unsigned char *buf,
182 int len, int peek);
183static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap, 181static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap,
184 const unsigned char *seq); 182 const unsigned char *seq);
185static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap, 183static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap,
@@ -530,15 +528,7 @@ dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
530 return -1; 528 return -1;
531 } 529 }
532 530
533 /* check whether there's a handshake message (client hello?) waiting */ 531 if (!s->internal->in_handshake && SSL_in_init(s)) {
534 if ((ret = have_handshake_fragment(s, type, buf, len, peek)))
535 return ret;
536
537 /* Now D1I(s)->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. */
538
539 if (!s->internal->in_handshake && SSL_in_init(s))
540 {
541 /* type == SSL3_RT_APPLICATION_DATA */
542 i = s->internal->handshake_func(s); 532 i = s->internal->handshake_func(s);
543 if (i < 0) 533 if (i < 0)
544 return (i); 534 return (i);
@@ -645,89 +635,62 @@ dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
645 return (n); 635 return (n);
646 } 636 }
647 637
648 638 /*
649 /* If we get here, then type != rr->type; if we have a handshake 639 * If we get here, then type != rr->type; if we have a handshake
650 * message, then it was unexpected (Hello Request or Client Hello). */ 640 * message, then it was unexpected (Hello Request or Client Hello).
651
652 /* In case of record types for which we have 'fragment' storage,
653 * fill that so that we can process the data at a fixed place.
654 */ 641 */
642
655 { 643 {
656 unsigned int k, dest_maxlen = 0; 644 unsigned int record_min_len = 0;
657 unsigned char *dest = NULL;
658 unsigned int *dest_len = NULL;
659 645
660 if (rr->type == SSL3_RT_HANDSHAKE) { 646 if (rr->type == SSL3_RT_HANDSHAKE) {
661 dest_maxlen = sizeof D1I(s)->handshake_fragment; 647 record_min_len = DTLS1_HM_HEADER_LENGTH;
662 dest = D1I(s)->handshake_fragment;
663 dest_len = &D1I(s)->handshake_fragment_len;
664 } else if (rr->type == SSL3_RT_ALERT) { 648 } else if (rr->type == SSL3_RT_ALERT) {
665 dest_maxlen = sizeof(D1I(s)->alert_fragment); 649 record_min_len = DTLS1_AL_HEADER_LENGTH;
666 dest = D1I(s)->alert_fragment; 650 } else if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC) {
667 dest_len = &D1I(s)->alert_fragment_len; 651 record_min_len = DTLS1_CCS_HEADER_LENGTH;
668 } 652 } else if (rr->type == SSL3_RT_APPLICATION_DATA) {
669 /* else it's a CCS message, or application data or wrong */ 653 /*
670 else if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC) { 654 * Application data while renegotiating is allowed.
671 /* Application data while renegotiating 655 * Try reading again.
672 * is allowed. Try again reading.
673 */ 656 */
674 if (rr->type == SSL3_RT_APPLICATION_DATA) { 657 BIO *bio;
675 BIO *bio;
676 S3I(s)->in_read_app_data = 2;
677 bio = SSL_get_rbio(s);
678 s->internal->rwstate = SSL_READING;
679 BIO_clear_retry_flags(bio);
680 BIO_set_retry_read(bio);
681 return (-1);
682 }
683 658
659 S3I(s)->in_read_app_data = 2;
660 bio = SSL_get_rbio(s);
661 s->internal->rwstate = SSL_READING;
662 BIO_clear_retry_flags(bio);
663 BIO_set_retry_read(bio);
664 return (-1);
665 } else {
684 /* Not certain if this is the right error handling */ 666 /* Not certain if this is the right error handling */
685 al = SSL_AD_UNEXPECTED_MESSAGE; 667 al = SSL_AD_UNEXPECTED_MESSAGE;
686 SSLerror(s, SSL_R_UNEXPECTED_RECORD); 668 SSLerror(s, SSL_R_UNEXPECTED_RECORD);
687 goto fatal_err; 669 goto fatal_err;
688 } 670 }
689 671
690 if (dest_maxlen > 0) { 672 if (record_min_len > 0 && rr->length < record_min_len) {
691 /* XDTLS: In a pathalogical case, the Client Hello 673 s->internal->rstate = SSL_ST_READ_HEADER;
692 * may be fragmented--don't always expect dest_maxlen bytes */ 674 rr->length = 0;
693 if (rr->length < dest_maxlen) { 675 goto start;
694 s->internal->rstate = SSL_ST_READ_HEADER;
695 rr->length = 0;
696 goto start;
697 }
698
699 /* now move 'n' bytes: */
700 for ( k = 0; k < dest_maxlen; k++) {
701 dest[k] = rr->data[rr->off++];
702 rr->length--;
703 }
704 *dest_len = dest_maxlen;
705 } 676 }
706 } 677 }
707 678
708 /* D1I(s)->handshake_fragment_len == 12 iff rr->type == SSL3_RT_HANDSHAKE;
709 * D1I(s)->alert_fragment_len == 7 iff rr->type == SSL3_RT_ALERT.
710 * (Possibly rr is 'empty' now, i.e. rr->length may be 0.) */
711
712 /* If we are a client, check for an incoming 'Hello Request': */ 679 /* If we are a client, check for an incoming 'Hello Request': */
713 if ((!s->server) && 680 if (!s->server && rr->type == SSL3_RT_HANDSHAKE &&
714 (D1I(s)->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) && 681 rr->length >= DTLS1_HM_HEADER_LENGTH && rr->off == 0 &&
715 (D1I(s)->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) && 682 rr->data[0] == SSL3_MT_HELLO_REQUEST &&
716 (s->session != NULL) && (s->session->cipher != NULL)) { 683 s->session != NULL && s->session->cipher != NULL) {
717 D1I(s)->handshake_fragment_len = 0; 684 if (rr->data[1] != 0 || rr->data[2] != 0 || rr->data[3] != 0) {
718
719 if ((D1I(s)->handshake_fragment[1] != 0) ||
720 (D1I(s)->handshake_fragment[2] != 0) ||
721 (D1I(s)->handshake_fragment[3] != 0)) {
722 al = SSL_AD_DECODE_ERROR; 685 al = SSL_AD_DECODE_ERROR;
723 SSLerror(s, SSL_R_BAD_HELLO_REQUEST); 686 SSLerror(s, SSL_R_BAD_HELLO_REQUEST);
724 goto fatal_err; 687 goto fatal_err;
725 } 688 }
689 rr->length = 0;
726 690
727 /* no need to check sequence number on HELLO REQUEST messages */ 691 /* no need to check sequence number on HELLO REQUEST messages */
728 692
729 ssl_msg_callback(s, 0, SSL3_RT_HANDSHAKE, 693 ssl_msg_callback(s, 0, SSL3_RT_HANDSHAKE, rr->data, 4);
730 D1I(s)->handshake_fragment, 4);
731 694
732 if (SSL_is_init_finished(s) && 695 if (SSL_is_init_finished(s) &&
733 !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) && 696 !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) &&
@@ -763,16 +726,16 @@ dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
763 } 726 }
764 /* we either finished a handshake or ignored the request, 727 /* we either finished a handshake or ignored the request,
765 * now try again to obtain the (application) data we were asked for */ 728 * now try again to obtain the (application) data we were asked for */
729 rr->length = 0;
766 goto start; 730 goto start;
767 } 731 }
768 732
769 if (D1I(s)->alert_fragment_len >= DTLS1_AL_HEADER_LENGTH) { 733 if (rr->type == SSL3_RT_ALERT && rr->length >= DTLS1_AL_HEADER_LENGTH &&
770 int alert_level = D1I(s)->alert_fragment[0]; 734 rr->off == 0) {
771 int alert_descr = D1I(s)->alert_fragment[1]; 735 int alert_level = rr->data[0];
772 736 int alert_descr = rr->data[1];
773 D1I(s)->alert_fragment_len = 0;
774 737
775 ssl_msg_callback(s, 0, SSL3_RT_ALERT, D1I(s)->alert_fragment, 2); 738 ssl_msg_callback(s, 0, SSL3_RT_ALERT, rr->data, 2);
776 739
777 ssl_info_callback(s, SSL_CB_READ_ALERT, 740 ssl_info_callback(s, SSL_CB_READ_ALERT,
778 (alert_level << 8) | alert_descr); 741 (alert_level << 8) | alert_descr);
@@ -798,11 +761,11 @@ dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
798 goto fatal_err; 761 goto fatal_err;
799 } 762 }
800 763
764 rr->length = 0;
801 goto start; 765 goto start;
802 } 766 }
803 767
804 if (s->internal->shutdown & SSL_SENT_SHUTDOWN) /* but we have not received a shutdown */ 768 if (s->internal->shutdown & SSL_SENT_SHUTDOWN) {
805 {
806 s->internal->rwstate = SSL_NOTHING; 769 s->internal->rwstate = SSL_NOTHING;
807 rr->length = 0; 770 rr->length = 0;
808 return (0); 771 return (0);
@@ -819,14 +782,13 @@ dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
819 goto fatal_err; 782 goto fatal_err;
820 } 783 }
821 784
822 rr->length = 0;
823
824 ssl_msg_callback(s, 0, SSL3_RT_CHANGE_CIPHER_SPEC, rr->data, 1); 785 ssl_msg_callback(s, 0, SSL3_RT_CHANGE_CIPHER_SPEC, rr->data, 1);
825 786
826 /* We can't process a CCS now, because previous handshake 787 /* We can't process a CCS now, because previous handshake
827 * messages are still missing, so just drop it. 788 * messages are still missing, so just drop it.
828 */ 789 */
829 if (!D1I(s)->change_cipher_spec_ok) { 790 if (!D1I(s)->change_cipher_spec_ok) {
791 rr->length = 0;
830 goto start; 792 goto start;
831 } 793 }
832 794
@@ -836,11 +798,13 @@ dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
836 if (!ssl3_do_change_cipher_spec(s)) 798 if (!ssl3_do_change_cipher_spec(s))
837 goto err; 799 goto err;
838 800
801 rr->length = 0;
839 goto start; 802 goto start;
840 } 803 }
841 804
842 /* Unexpected handshake message (Client Hello, or protocol violation) */ 805 /* Unexpected handshake message (Client Hello, or protocol violation) */
843 if ((D1I(s)->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) && 806 if (rr->type == SSL3_RT_HANDSHAKE &&
807 rr->length >= DTLS1_HM_HEADER_LENGTH && rr->off == 0 &&
844 !s->internal->in_handshake) { 808 !s->internal->in_handshake) {
845 struct hm_header_st msg_hdr; 809 struct hm_header_st msg_hdr;
846 810
@@ -893,6 +857,7 @@ dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
893 return (-1); 857 return (-1);
894 } 858 }
895 } 859 }
860 rr->length = 0;
896 goto start; 861 goto start;
897 } 862 }
898 863
@@ -967,39 +932,6 @@ dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, int len)
967 return i; 932 return i;
968} 933}
969 934
970
971 /* this only happens when a client hello is received and a handshake
972 * is started. */
973static int
974have_handshake_fragment(SSL *s, int type, unsigned char *buf,
975 int len, int peek)
976{
977
978 if ((type == SSL3_RT_HANDSHAKE) && (D1I(s)->handshake_fragment_len > 0))
979 /* (partially) satisfy request from storage */
980 {
981 unsigned char *src = D1I(s)->handshake_fragment;
982 unsigned char *dst = buf;
983 unsigned int k, n;
984
985 /* peek == 0 */
986 n = 0;
987 while ((len > 0) && (D1I(s)->handshake_fragment_len > 0)) {
988 *dst++ = *src++;
989 len--;
990 D1I(s)->handshake_fragment_len--;
991 n++;
992 }
993 /* move any remaining fragment bytes: */
994 for (k = 0; k < D1I(s)->handshake_fragment_len; k++)
995 D1I(s)->handshake_fragment[k] = *src++;
996 return n;
997 }
998
999 return 0;
1000}
1001
1002
1003/* Call this to write data in records of type 'type' 935/* Call this to write data in records of type 'type'
1004 * It will return <= 0 if not all data has been sent or non-blocking IO. 936 * It will return <= 0 if not all data has been sent or non-blocking IO.
1005 */ 937 */
diff --git a/src/lib/libssl/dtls_locl.h b/src/lib/libssl/dtls_locl.h
index 83fb9e0e10..502b42dcdd 100644
--- a/src/lib/libssl/dtls_locl.h
+++ b/src/lib/libssl/dtls_locl.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: dtls_locl.h,v 1.5 2021/08/30 19:12:25 jsing Exp $ */ 1/* $OpenBSD: dtls_locl.h,v 1.6 2021/08/31 13:34:55 jsing Exp $ */
2/* 2/*
3 * DTLS implementation written by Nagendra Modadugu 3 * DTLS implementation written by Nagendra Modadugu
4 * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. 4 * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
@@ -167,13 +167,6 @@ typedef struct dtls1_state_internal_st {
167 167
168 struct dtls1_timeout_st timeout; 168 struct dtls1_timeout_st timeout;
169 169
170 /* storage for Alert/Handshake protocol data received but not
171 * yet processed by ssl3_read_bytes: */
172 unsigned char alert_fragment[DTLS1_AL_HEADER_LENGTH];
173 unsigned int alert_fragment_len;
174 unsigned char handshake_fragment[DTLS1_HM_HEADER_LENGTH];
175 unsigned int handshake_fragment_len;
176
177 unsigned int retransmitting; 170 unsigned int retransmitting;
178 unsigned int change_cipher_spec_ok; 171 unsigned int change_cipher_spec_ok;
179} DTLS1_STATE_INTERNAL; 172} DTLS1_STATE_INTERNAL;