summaryrefslogtreecommitdiff
path: root/src/ssl/s3_pkt.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/ssl/s3_pkt.cc')
-rw-r--r--src/ssl/s3_pkt.cc24
1 files changed, 21 insertions, 3 deletions
diff --git a/src/ssl/s3_pkt.cc b/src/ssl/s3_pkt.cc
index abc6798e..a54bb001 100644
--- a/src/ssl/s3_pkt.cc
+++ b/src/ssl/s3_pkt.cc
@@ -118,6 +118,7 @@
#include <openssl/mem.h>
#include <openssl/rand.h>
+#include "../crypto/err/internal.h"
#include "../crypto/internal.h"
#include "internal.h"
@@ -381,7 +382,24 @@ ssl_open_record_t ssl3_open_change_cipher_spec(SSL *ssl, size_t *out_consumed,
return ssl_open_record_success;
}
-int ssl_send_alert(SSL *ssl, int level, int desc) {
+void ssl_send_alert(SSL *ssl, int level, int desc) {
+ // This function is called in response to a fatal error from the peer. Ignore
+ // any failures writing the alert and report only the original error. In
+ // particular, if the transport uses |SSL_write|, our existing error will be
+ // clobbered so we must save and restore the error queue. See
+ // https://crbug.com/959305.
+ //
+ // TODO(davidben): Return the alert out of the handshake, rather than calling
+ // this function internally everywhere.
+ //
+ // TODO(davidben): This does not allow retrying if the alert hit EAGAIN. See
+ // https://crbug.com/boringssl/130.
+ UniquePtr<ERR_SAVE_STATE> err_state(ERR_save_state());
+ ssl_send_alert_impl(ssl, level, desc);
+ ERR_restore_state(err_state.get());
+}
+
+int ssl_send_alert_impl(SSL *ssl, int level, int desc) {
// It is illegal to send an alert when we've already sent a closing one.
if (ssl->s3->write_shutdown != ssl_shutdown_none) {
OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN);
@@ -396,7 +414,7 @@ int ssl_send_alert(SSL *ssl, int level, int desc) {
ssl->s3->write_shutdown = ssl_shutdown_error;
}
- ssl->s3->alert_dispatch = 1;
+ ssl->s3->alert_dispatch = true;
ssl->s3->send_alert[0] = level;
ssl->s3->send_alert[1] = desc;
if (ssl->s3->write_buffer.empty()) {
@@ -423,7 +441,7 @@ int ssl3_dispatch_alert(SSL *ssl) {
}
}
- ssl->s3->alert_dispatch = 0;
+ ssl->s3->alert_dispatch = false;
// If the alert is fatal, flush the BIO now.
if (ssl->s3->send_alert[0] == SSL3_AL_FATAL) {