diff options
author | jsing <> | 2020-02-19 18:22:54 +0000 |
---|---|---|
committer | jsing <> | 2020-02-19 18:22:54 +0000 |
commit | 694792031e2b5887b3d073ebd3dabfa6e7a60fad (patch) | |
tree | c4b2636bacbae90e01b0d5b98ce6d9d3491875ee /src/lib/libssl/ssl_pkt.c | |
parent | 67f0f449c8bd353252d1a7498100c115256c6979 (diff) | |
download | openbsd-694792031e2b5887b3d073ebd3dabfa6e7a60fad.tar.gz openbsd-694792031e2b5887b3d073ebd3dabfa6e7a60fad.tar.bz2 openbsd-694792031e2b5887b3d073ebd3dabfa6e7a60fad.zip |
Refactor do_ssl3_write().
When empty fragments were added as a countermeasure against chosen
plaintext attacks on CBC, it was done by adding a recursive call to
do_ssl3_write(). This makes the code more complex and difficult to change.
Split the record creation code into a separate ssl3_create_record()
function, which do_ssl3_write() calls. In the case where an empty fragment
is needed, ssl3_create_record() is simply called twice, removing the need
for recursion.
ok inoguchi@ tb@
Diffstat (limited to 'src/lib/libssl/ssl_pkt.c')
-rw-r--r-- | src/lib/libssl/ssl_pkt.c | 195 |
1 files changed, 98 insertions, 97 deletions
diff --git a/src/lib/libssl/ssl_pkt.c b/src/lib/libssl/ssl_pkt.c index 2a0dd68acb..e7bbf37bcd 100644 --- a/src/lib/libssl/ssl_pkt.c +++ b/src/lib/libssl/ssl_pkt.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssl_pkt.c,v 1.16 2019/03/19 16:53:03 jsing Exp $ */ | 1 | /* $OpenBSD: ssl_pkt.c,v 1.17 2020/02/19 18:22:54 jsing Exp $ */ |
2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
3 | * All rights reserved. | 3 | * All rights reserved. |
4 | * | 4 | * |
@@ -120,7 +120,7 @@ | |||
120 | #include "bytestring.h" | 120 | #include "bytestring.h" |
121 | 121 | ||
122 | static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, | 122 | static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, |
123 | unsigned int len, int create_empty_fragment); | 123 | unsigned int len); |
124 | static int ssl3_get_record(SSL *s); | 124 | static int ssl3_get_record(SSL *s); |
125 | 125 | ||
126 | /* | 126 | /* |
@@ -596,7 +596,7 @@ ssl3_write_bytes(SSL *s, int type, const void *buf_, int len) | |||
596 | else | 596 | else |
597 | nw = n; | 597 | nw = n; |
598 | 598 | ||
599 | i = do_ssl3_write(s, type, &(buf[tot]), nw, 0); | 599 | i = do_ssl3_write(s, type, &(buf[tot]), nw); |
600 | if (i <= 0) { | 600 | if (i <= 0) { |
601 | S3I(s)->wnum = tot; | 601 | S3I(s)->wnum = tot; |
602 | return i; | 602 | return i; |
@@ -620,44 +620,14 @@ ssl3_write_bytes(SSL *s, int type, const void *buf_, int len) | |||
620 | } | 620 | } |
621 | 621 | ||
622 | static int | 622 | static int |
623 | do_ssl3_write(SSL *s, int type, const unsigned char *buf, | 623 | ssl3_create_record(SSL *s, unsigned char *p, int type, const unsigned char *buf, |
624 | unsigned int len, int create_empty_fragment) | 624 | unsigned int len) |
625 | { | 625 | { |
626 | unsigned char *p, *plen; | 626 | SSL3_RECORD *wr = &(S3I(s)->wrec); |
627 | int i, mac_size, clear = 0; | 627 | SSL_SESSION *sess = s->session; |
628 | int prefix_len = 0; | 628 | unsigned char *plen; |
629 | int eivlen; | 629 | int eivlen, mac_size; |
630 | size_t align; | 630 | int clear = 0; |
631 | SSL3_RECORD *wr; | ||
632 | SSL3_BUFFER *wb = &(S3I(s)->wbuf); | ||
633 | SSL_SESSION *sess; | ||
634 | |||
635 | if (wb->buf == NULL) | ||
636 | if (!ssl3_setup_write_buffer(s)) | ||
637 | return -1; | ||
638 | |||
639 | /* first check if there is a SSL3_BUFFER still being written | ||
640 | * out. This will happen with non blocking IO */ | ||
641 | if (wb->left != 0) | ||
642 | return (ssl3_write_pending(s, type, buf, len)); | ||
643 | |||
644 | /* If we have an alert to send, lets send it */ | ||
645 | if (S3I(s)->alert_dispatch) { | ||
646 | i = s->method->ssl_dispatch_alert(s); | ||
647 | if (i <= 0) | ||
648 | return (i); | ||
649 | /* if it went, fall through and send more stuff */ | ||
650 | /* we may have released our buffer, so get it again */ | ||
651 | if (wb->buf == NULL) | ||
652 | if (!ssl3_setup_write_buffer(s)) | ||
653 | return -1; | ||
654 | } | ||
655 | |||
656 | if (len == 0 && !create_empty_fragment) | ||
657 | return 0; | ||
658 | |||
659 | wr = &(S3I(s)->wrec); | ||
660 | sess = s->session; | ||
661 | 631 | ||
662 | if ((sess == NULL) || (s->internal->enc_write_ctx == NULL) || | 632 | if ((sess == NULL) || (s->internal->enc_write_ctx == NULL) || |
663 | (EVP_MD_CTX_md(s->internal->write_hash) == NULL)) { | 633 | (EVP_MD_CTX_md(s->internal->write_hash) == NULL)) { |
@@ -669,56 +639,6 @@ do_ssl3_write(SSL *s, int type, const unsigned char *buf, | |||
669 | goto err; | 639 | goto err; |
670 | } | 640 | } |
671 | 641 | ||
672 | /* | ||
673 | * 'create_empty_fragment' is true only when this function calls | ||
674 | * itself. | ||
675 | */ | ||
676 | if (!clear && !create_empty_fragment && !S3I(s)->empty_fragment_done) { | ||
677 | /* | ||
678 | * Countermeasure against known-IV weakness in CBC ciphersuites | ||
679 | * (see http://www.openssl.org/~bodo/tls-cbc.txt) | ||
680 | */ | ||
681 | if (S3I(s)->need_empty_fragments && | ||
682 | type == SSL3_RT_APPLICATION_DATA) { | ||
683 | /* recursive function call with 'create_empty_fragment' set; | ||
684 | * this prepares and buffers the data for an empty fragment | ||
685 | * (these 'prefix_len' bytes are sent out later | ||
686 | * together with the actual payload) */ | ||
687 | prefix_len = do_ssl3_write(s, type, buf, 0, 1); | ||
688 | if (prefix_len <= 0) | ||
689 | goto err; | ||
690 | |||
691 | if (prefix_len > | ||
692 | (SSL3_RT_HEADER_LENGTH + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD)) { | ||
693 | /* insufficient space */ | ||
694 | SSLerror(s, ERR_R_INTERNAL_ERROR); | ||
695 | goto err; | ||
696 | } | ||
697 | } | ||
698 | |||
699 | S3I(s)->empty_fragment_done = 1; | ||
700 | } | ||
701 | |||
702 | if (create_empty_fragment) { | ||
703 | /* extra fragment would be couple of cipher blocks, | ||
704 | * which would be multiple of SSL3_ALIGN_PAYLOAD, so | ||
705 | * if we want to align the real payload, then we can | ||
706 | * just pretent we simply have two headers. */ | ||
707 | align = (size_t)wb->buf + 2 * SSL3_RT_HEADER_LENGTH; | ||
708 | align = (-align) & (SSL3_ALIGN_PAYLOAD - 1); | ||
709 | |||
710 | p = wb->buf + align; | ||
711 | wb->offset = align; | ||
712 | } else if (prefix_len) { | ||
713 | p = wb->buf + wb->offset + prefix_len; | ||
714 | } else { | ||
715 | align = (size_t)wb->buf + SSL3_RT_HEADER_LENGTH; | ||
716 | align = (-align) & (SSL3_ALIGN_PAYLOAD - 1); | ||
717 | |||
718 | p = wb->buf + align; | ||
719 | wb->offset = align; | ||
720 | } | ||
721 | |||
722 | /* write the header */ | 642 | /* write the header */ |
723 | 643 | ||
724 | *(p++) = type&0xff; | 644 | *(p++) = type&0xff; |
@@ -767,8 +687,7 @@ do_ssl3_write(SSL *s, int type, const unsigned char *buf, | |||
767 | * wr->data still points in the wb->buf */ | 687 | * wr->data still points in the wb->buf */ |
768 | 688 | ||
769 | if (mac_size != 0) { | 689 | if (mac_size != 0) { |
770 | if (tls1_mac(s, | 690 | if (tls1_mac(s, &(p[wr->length + eivlen]), 1) < 0) |
771 | &(p[wr->length + eivlen]), 1) < 0) | ||
772 | goto err; | 691 | goto err; |
773 | wr->length += mac_size; | 692 | wr->length += mac_size; |
774 | } | 693 | } |
@@ -795,13 +714,95 @@ do_ssl3_write(SSL *s, int type, const unsigned char *buf, | |||
795 | wr->type=type; /* not needed but helps for debugging */ | 714 | wr->type=type; /* not needed but helps for debugging */ |
796 | wr->length += SSL3_RT_HEADER_LENGTH; | 715 | wr->length += SSL3_RT_HEADER_LENGTH; |
797 | 716 | ||
798 | if (create_empty_fragment) { | 717 | return 1; |
799 | /* we are in a recursive call; | 718 | |
800 | * just return the length, don't write out anything here | 719 | err: |
720 | return 0; | ||
721 | } | ||
722 | |||
723 | static int | ||
724 | do_ssl3_write(SSL *s, int type, const unsigned char *buf, unsigned int len) | ||
725 | { | ||
726 | SSL3_RECORD *wr = &(S3I(s)->wrec); | ||
727 | SSL3_BUFFER *wb = &(S3I(s)->wbuf); | ||
728 | SSL_SESSION *sess = s->session; | ||
729 | unsigned char *p; | ||
730 | int i, clear = 0; | ||
731 | int prefix_len = 0; | ||
732 | size_t align; | ||
733 | |||
734 | if (wb->buf == NULL) | ||
735 | if (!ssl3_setup_write_buffer(s)) | ||
736 | return -1; | ||
737 | |||
738 | /* first check if there is a SSL3_BUFFER still being written | ||
739 | * out. This will happen with non blocking IO */ | ||
740 | if (wb->left != 0) | ||
741 | return (ssl3_write_pending(s, type, buf, len)); | ||
742 | |||
743 | /* If we have an alert to send, lets send it */ | ||
744 | if (S3I(s)->alert_dispatch) { | ||
745 | i = s->method->ssl_dispatch_alert(s); | ||
746 | if (i <= 0) | ||
747 | return (i); | ||
748 | /* if it went, fall through and send more stuff */ | ||
749 | /* we may have released our buffer, so get it again */ | ||
750 | if (wb->buf == NULL) | ||
751 | if (!ssl3_setup_write_buffer(s)) | ||
752 | return -1; | ||
753 | } | ||
754 | |||
755 | if (len == 0) | ||
756 | return 0; | ||
757 | |||
758 | align = (size_t)wb->buf + SSL3_RT_HEADER_LENGTH; | ||
759 | align = (-align) & (SSL3_ALIGN_PAYLOAD - 1); | ||
760 | |||
761 | p = wb->buf + align; | ||
762 | wb->offset = align; | ||
763 | |||
764 | if ((sess == NULL) || (s->internal->enc_write_ctx == NULL) || | ||
765 | (EVP_MD_CTX_md(s->internal->write_hash) == NULL)) { | ||
766 | clear = s->internal->enc_write_ctx ? 0 : 1; /* must be AEAD cipher */ | ||
767 | } | ||
768 | |||
769 | if (!clear && !S3I(s)->empty_fragment_done) { | ||
770 | /* | ||
771 | * Countermeasure against known-IV weakness in CBC ciphersuites | ||
772 | * (see http://www.openssl.org/~bodo/tls-cbc.txt) | ||
801 | */ | 773 | */ |
802 | return wr->length; | 774 | if (S3I(s)->need_empty_fragments && |
775 | type == SSL3_RT_APPLICATION_DATA) { | ||
776 | /* extra fragment would be couple of cipher blocks, | ||
777 | * which would be multiple of SSL3_ALIGN_PAYLOAD, so | ||
778 | * if we want to align the real payload, then we can | ||
779 | * just pretent we simply have two headers. */ | ||
780 | align = (size_t)wb->buf + 2 * SSL3_RT_HEADER_LENGTH; | ||
781 | align = (-align) & (SSL3_ALIGN_PAYLOAD - 1); | ||
782 | |||
783 | p = wb->buf + align; | ||
784 | wb->offset = align; | ||
785 | |||
786 | if (!ssl3_create_record(s, p, type, buf, 0)) | ||
787 | goto err; | ||
788 | |||
789 | prefix_len = wr->length; | ||
790 | if (prefix_len > (SSL3_RT_HEADER_LENGTH + | ||
791 | SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD)) { | ||
792 | /* insufficient space */ | ||
793 | SSLerror(s, ERR_R_INTERNAL_ERROR); | ||
794 | goto err; | ||
795 | } | ||
796 | |||
797 | p = wb->buf + wb->offset + prefix_len; | ||
798 | } | ||
799 | |||
800 | S3I(s)->empty_fragment_done = 1; | ||
803 | } | 801 | } |
804 | 802 | ||
803 | if (!ssl3_create_record(s, p, type, buf, len)) | ||
804 | goto err; | ||
805 | |||
805 | /* now let's set up wb */ | 806 | /* now let's set up wb */ |
806 | wb->left = prefix_len + wr->length; | 807 | wb->left = prefix_len + wr->length; |
807 | 808 | ||
@@ -1421,7 +1422,7 @@ ssl3_dispatch_alert(SSL *s) | |||
1421 | void (*cb)(const SSL *ssl, int type, int val) = NULL; | 1422 | void (*cb)(const SSL *ssl, int type, int val) = NULL; |
1422 | 1423 | ||
1423 | S3I(s)->alert_dispatch = 0; | 1424 | S3I(s)->alert_dispatch = 0; |
1424 | i = do_ssl3_write(s, SSL3_RT_ALERT, &S3I(s)->send_alert[0], 2, 0); | 1425 | i = do_ssl3_write(s, SSL3_RT_ALERT, &S3I(s)->send_alert[0], 2); |
1425 | if (i <= 0) { | 1426 | if (i <= 0) { |
1426 | S3I(s)->alert_dispatch = 1; | 1427 | S3I(s)->alert_dispatch = 1; |
1427 | } else { | 1428 | } else { |