diff options
author | Azat Khuzhin <azat@libevent.org> | 2020-10-31 21:45:22 +0300 |
---|---|---|
committer | Azat Khuzhin <azat@libevent.org> | 2020-10-31 22:51:40 +0300 |
commit | 7e0fc878c5646f45273f38dbf5b8d325a20c81df (patch) | |
tree | e68ab53a93f59853b6bd2dfc21774e789d11c971 | |
parent | 587f6c83a3557c048fce6e541e7fc534082b0e85 (diff) | |
download | libevent-7e0fc878c5646f45273f38dbf5b8d325a20c81df.tar.gz |
Introduce new API for flags of the SSL bufferevent
Introduce more generic API (like for evbuffer):
- bufferevent_ssl_set_flags()
- bufferevent_ssl_clear_flags()
- bufferevent_ssl_get_flags()
And deprecate existing:
- bufferevent_openssl_get_allow_dirty_shutdown()
- bufferevent_openssl_set_allow_dirty_shutdown()
- bufferevent_mbedtls_get_allow_dirty_shutdown()
- bufferevent_mbedtls_set_allow_dirty_shutdown()
-rw-r--r-- | bufferevent_mbedtls.c | 2 | ||||
-rw-r--r-- | bufferevent_openssl.c | 2 | ||||
-rw-r--r-- | bufferevent_ssl.c | 84 | ||||
-rw-r--r-- | include/event2/bufferevent_ssl.h | 102 | ||||
-rw-r--r-- | ssl-compat.h | 4 |
5 files changed, 141 insertions, 53 deletions
diff --git a/bufferevent_mbedtls.c b/bufferevent_mbedtls.c index e188abed..e535c86f 100644 --- a/bufferevent_mbedtls.c +++ b/bufferevent_mbedtls.c @@ -210,7 +210,7 @@ conn_closed(struct bufferevent_ssl *bev_ssl, int when, int errcode, int ret) char buf[100]; if (when & BEV_EVENT_READING && ret == 0) { - if (bev_ssl->allow_dirty_shutdown) + if (bev_ssl->flags & BUFFEREVENT_SSL_DIRTY_SHUTDOWN) event = BEV_EVENT_EOF; } else { mbedtls_strerror(errcode, buf, sizeof(buf)); diff --git a/bufferevent_openssl.c b/bufferevent_openssl.c index 34259ce5..6ace1e3a 100644 --- a/bufferevent_openssl.c +++ b/bufferevent_openssl.c @@ -281,7 +281,7 @@ conn_closed(struct bufferevent_ssl *bev_ssl, int when, int errcode, int ret) bufferevent_ssl_put_error(bev_ssl, err); } - if (dirty_shutdown && bev_ssl->allow_dirty_shutdown) + if (dirty_shutdown && bev_ssl->flags & BUFFEREVENT_SSL_DIRTY_SHUTDOWN) event = BEV_EVENT_EOF; bufferevent_ssl_stop_reading(bev_ssl); diff --git a/bufferevent_ssl.c b/bufferevent_ssl.c index 5c6956d5..dd013c98 100644 --- a/bufferevent_ssl.c +++ b/bufferevent_ssl.c @@ -581,7 +581,7 @@ be_ssl_eventcb(struct bufferevent *bev_base, short what, void *ctx) int event = 0; if (what & BEV_EVENT_EOF) { - if (bev_ssl->allow_dirty_shutdown) + if (bev_ssl->flags & BUFFEREVENT_SSL_DIRTY_SHUTDOWN) event = BEV_EVENT_EOF; else event = BEV_EVENT_ERROR; @@ -1052,41 +1052,91 @@ err: return NULL; } -int -bufferevent_ssl_get_allow_dirty_shutdown(struct bufferevent *bev) +unsigned long +bufferevent_get_ssl_error(struct bufferevent *bev) { - int allow_dirty_shutdown = -1; + unsigned long err = 0; struct bufferevent_ssl *bev_ssl; BEV_LOCK(bev); bev_ssl = bufferevent_ssl_upcast(bev); - if (bev_ssl) - allow_dirty_shutdown = bev_ssl->allow_dirty_shutdown; + if (bev_ssl && bev_ssl->n_errors) { + err = bev_ssl->errors[--bev_ssl->n_errors]; + } BEV_UNLOCK(bev); - return allow_dirty_shutdown; + return err; } -void -bufferevent_ssl_set_allow_dirty_shutdown(struct bufferevent *bev, - int allow_dirty_shutdown) +ev_uint64_t bufferevent_ssl_get_flags(struct bufferevent *bev) { + ev_uint64_t flags = EV_UINT64_MAX; struct bufferevent_ssl *bev_ssl; + BEV_LOCK(bev); bev_ssl = bufferevent_ssl_upcast(bev); if (bev_ssl) - bev_ssl->allow_dirty_shutdown = !!allow_dirty_shutdown; + flags = bev_ssl->flags; BEV_UNLOCK(bev); + + return flags; } +ev_uint64_t bufferevent_ssl_set_flags(struct bufferevent *bev, ev_uint64_t flags) +{ + ev_uint64_t old_flags = EV_UINT64_MAX; + struct bufferevent_ssl *bev_ssl; -unsigned long -bufferevent_get_ssl_error(struct bufferevent *bev) + flags &= (BUFFEREVENT_SSL_DIRTY_SHUTDOWN); + if (!flags) + return old_flags; + + BEV_LOCK(bev); + bev_ssl = bufferevent_ssl_upcast(bev); + if (bev_ssl) { + old_flags = bev_ssl->flags; + bev_ssl->flags |= flags; + } + BEV_UNLOCK(bev); + + return old_flags; +} +ev_uint64_t bufferevent_ssl_clear_flags(struct bufferevent *bev, ev_uint64_t flags) { - unsigned long err = 0; + ev_uint64_t old_flags = EV_UINT64_MAX; struct bufferevent_ssl *bev_ssl; + + flags &= (BUFFEREVENT_SSL_DIRTY_SHUTDOWN); + if (!flags) + return old_flags; + BEV_LOCK(bev); bev_ssl = bufferevent_ssl_upcast(bev); - if (bev_ssl && bev_ssl->n_errors) { - err = bev_ssl->errors[--bev_ssl->n_errors]; + if (bev_ssl) { + old_flags = bev_ssl->flags; + bev_ssl->flags &= ~flags; } BEV_UNLOCK(bev); - return err; + + return old_flags; +} + +int +bufferevent_ssl_get_allow_dirty_shutdown(struct bufferevent *bev) +{ + ev_uint64_t flags = bufferevent_ssl_get_flags(bev); + if (flags == EV_UINT64_MAX) + return flags; + return !!(flags & BUFFEREVENT_SSL_DIRTY_SHUTDOWN); +} + +void +bufferevent_ssl_set_allow_dirty_shutdown( + struct bufferevent *bev, int allow_dirty_shutdown) +{ + BEV_LOCK(bev); + + if (allow_dirty_shutdown) + bufferevent_ssl_set_flags(bev, BUFFEREVENT_SSL_DIRTY_SHUTDOWN); + else + bufferevent_ssl_clear_flags(bev, BUFFEREVENT_SSL_DIRTY_SHUTDOWN); + + BEV_UNLOCK(bev); } diff --git a/include/event2/bufferevent_ssl.h b/include/event2/bufferevent_ssl.h index 69fb40b7..5abcb790 100644 --- a/include/event2/bufferevent_ssl.h +++ b/include/event2/bufferevent_ssl.h @@ -49,6 +49,23 @@ enum bufferevent_ssl_state { BUFFEREVENT_SSL_ACCEPTING = 2 }; +/** Control how to report dirty SSL shutdowns. + + If the peer (or the network, or an attacker) closes the TCP + connection before closing the SSL channel, and the protocol is SSL >= v3, + this is a "dirty" shutdown. If BUFFEREVENT_SSL_DIRTY_SHUTDOWN is not set + (default), this is reported as BEV_EVENT_ERROR. + + If instead BUFFEREVENT_SSL_DIRTY_SHUTDOWN is set, a dirty shutdown is + reported as BEV_EVENT_EOF. + + (Note that if the protocol is < SSLv3, you will always receive + BEV_EVENT_EOF, since SSL 2 and earlier cannot distinguish a secure + connection close from a dirty one. This is one reason (among many) + not to use SSL 2.) +*/ +#define BUFFEREVENT_SSL_DIRTY_SHUTDOWN 1 + #if defined(EVENT__HAVE_OPENSSL) || defined(EVENT_IN_DOXYGEN_) /* This is what openssl's SSL objects are underneath. */ struct ssl_st; @@ -90,28 +107,51 @@ bufferevent_openssl_socket_new(struct event_base *base, enum bufferevent_ssl_state state, int options); -/** Control how to report dirty SSL shutdowns. - - If the peer (or the network, or an attacker) closes the TCP - connection before closing the SSL channel, and the protocol is SSL >= v3, - this is a "dirty" shutdown. If allow_dirty_shutdown is 0 (default), - this is reported as BEV_EVENT_ERROR. - - If instead allow_dirty_shutdown=1, a dirty shutdown is reported as - BEV_EVENT_EOF. - - (Note that if the protocol is < SSLv3, you will always receive - BEV_EVENT_EOF, since SSL 2 and earlier cannot distinguish a secure - connection close from a dirty one. This is one reason (among many) - not to use SSL 2.) -*/ - +/** + * Get value of the BUFFEREVENT_SSL_DIRTY_SHUTDOWN flag. + * + * @see BUFFEREVENT_SSL_DIRTY_SHUTDOWN + * @deprecated This function is deprecated, use bufferevent_ssl_get_flags() instead. + * @see bufferevent_ssl_get_flags() + */ EVENT2_EXPORT_SYMBOL int bufferevent_openssl_get_allow_dirty_shutdown(struct bufferevent *bev); +/** + * Set value of the BUFFEREVENT_SSL_DIRTY_SHUTDOWN flag. + * + * @see BUFFEREVENT_SSL_DIRTY_SHUTDOWN + * @deprecated This function is deprecated, use bufferevent_ssl_set_flags() instead. + * @see bufferevent_ssl_set_flags() + */ EVENT2_EXPORT_SYMBOL void bufferevent_openssl_set_allow_dirty_shutdown(struct bufferevent *bev, int allow_dirty_shutdown); +/** + * Get flags of the SSL bufferevent. + * + * @see BUFFEREVENT_SSL_* + * @return flags or SIZE_MAX in case of error (if bufferevent is not SSL). + */ +EVENT2_EXPORT_SYMBOL +ev_uint64_t bufferevent_ssl_get_flags(struct bufferevent *bev); +/** Change the flags that are set for an ssl bufferevent by adding more. + * + * @param bev the ssl bufferevent. + * @param flags One or more BUFFEREVENT_SSL_* options + * @return old flags success, EV_UINT64_MAX on failure. + */ +EVENT2_EXPORT_SYMBOL +ev_uint64_t bufferevent_ssl_set_flags(struct bufferevent *bev, ev_uint64_t flags); +/** Change the flags that are set for an ssl bufferevent by removing some. + * + * @param bev the bufferevent. + * @param flags One or more BUFFEREVENT_SSL_* options + * @return old flags success, EV_UINT64_MAX on failure. + */ +EVENT2_EXPORT_SYMBOL +ev_uint64_t bufferevent_ssl_clear_flags(struct bufferevent *bev, ev_uint64_t flags); + /** Return the underlying openssl SSL * object for an SSL bufferevent. */ EVENT2_EXPORT_SYMBOL struct ssl_st * @@ -165,24 +205,22 @@ bufferevent_mbedtls_socket_new(struct event_base *base, enum bufferevent_ssl_state state, int options); -/** Control how to report dirty SSL shutdowns. - - If the peer (or the network, or an attacker) closes the TCP - connection before closing the SSL channel, and the protocol is SSL >= v3, - this is a "dirty" shutdown. If allow_dirty_shutdown is 0 (default), - this is reported as BEV_EVENT_ERROR. - - If instead allow_dirty_shutdown=1, a dirty shutdown is reported as - BEV_EVENT_EOF. - - (Note that if the protocol is < SSLv3, you will always receive - BEV_EVENT_EOF, since SSL 2 and earlier cannot distinguish a secure - connection close from a dirty one. This is one reason (among many) - not to use SSL 2.) -*/ - +/** + * Get value of the BUFFEREVENT_SSL_DIRTY_SHUTDOWN flag. + * + * @see BUFFEREVENT_SSL_DIRTY_SHUTDOWN + * @deprecated This function is deprecated, use bufferevent_ssl_get_flags() instead. + * @see bufferevent_ssl_get_flags() + */ EVENT2_EXPORT_SYMBOL int bufferevent_mbedtls_get_allow_dirty_shutdown(struct bufferevent *bev); +/** + * Set value of the BUFFEREVENT_SSL_DIRTY_SHUTDOWN flag. + * + * @see BUFFEREVENT_SSL_DIRTY_SHUTDOWN + * @deprecated This function is deprecated, use bufferevent_ssl_set_flags() instead. + * @see bufferevent_ssl_set_flags() + */ EVENT2_EXPORT_SYMBOL void bufferevent_mbedtls_set_allow_dirty_shutdown(struct bufferevent *bev, int allow_dirty_shutdown); diff --git a/ssl-compat.h b/ssl-compat.h index a19c457f..4dccb52a 100644 --- a/ssl-compat.h +++ b/ssl-compat.h @@ -73,8 +73,6 @@ struct bufferevent_ssl { unsigned read_blocked_on_write : 1; /* When we next get data, we should say "write" instead of "read". */ unsigned write_blocked_on_read : 1; - /* Treat TCP close before SSL close on SSL >= v3 as clean EOF. */ - unsigned allow_dirty_shutdown : 1; /* XXX */ unsigned n_errors : 2; @@ -82,6 +80,8 @@ struct bufferevent_ssl { unsigned state : 2; /* If we reset fd, we sould reset state too */ unsigned old_state : 2; + + ev_uint64_t flags; }; struct bufferevent *bufferevent_ssl_new_impl(struct event_base *base, |