[openssl] master update
Matt Caswell
matt at openssl.org
Tue May 7 13:28:55 UTC 2019
The branch master has been updated
via 7c3a7561b536264b282f604efc959edad18807d7 (commit)
via 72fb59c72186c327e047cd29d8a66a4a323b9f3b (commit)
from 260a16f33682a819414fcba6161708a5e6bdff50 (commit)
- Log -----------------------------------------------------------------
commit 7c3a7561b536264b282f604efc959edad18807d7
Author: Boris Pismenny <borisp at mellanox.com>
Date: Sat Apr 13 17:20:35 2019 +0300
ssl: Add SSL_sendfile
This commit adds the SSL_sendfile call, which allows KTLS sockets to
transmit file using zero-copy semantics.
Signed-off-by: Boris Pismenny <borisp at mellanox.com>
Reviewed-by: Paul Dale <paul.dale at oracle.com>
Reviewed-by: Matt Caswell <matt at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/8727)
commit 72fb59c72186c327e047cd29d8a66a4a323b9f3b
Author: Boris Pismenny <borisp at mellanox.com>
Date: Thu Apr 11 16:24:42 2019 +0300
Linux ktls sendfile
This commit introduces support for Linux KTLS sendfile.
Sendfile semantics require the use of a kernel TLS socket to construct the TLS
record headers, encrypt and authenticate the data.
KTLS sendfile improves performance by avoiding the copy of file data into user
space, which is required today.
Signed-off-by: Boris Pismenny <borisp at mellanox.com>
Reviewed-by: Paul Dale <paul.dale at oracle.com>
Reviewed-by: Matt Caswell <matt at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/8727)
-----------------------------------------------------------------------
Summary of changes:
crypto/err/openssl.txt | 1 +
doc/man3/SSL_write.pod | 31 +++++++++++++-
include/internal/ktls.h | 15 +++++++
include/openssl/err.h | 1 +
include/openssl/ssl.h | 2 +
include/openssl/sslerr.h | 1 +
ssl/ssl_err.c | 1 +
ssl/ssl_lib.c | 67 +++++++++++++++++++++++++++++
test/sslapitest.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++-
util/libssl.num | 1 +
10 files changed, 226 insertions(+), 3 deletions(-)
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 8ad85f5..14a7e3b 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -1437,6 +1437,7 @@ SSL_F_SSL_RENEGOTIATE:516:SSL_renegotiate
SSL_F_SSL_RENEGOTIATE_ABBREVIATED:546:SSL_renegotiate_abbreviated
SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT:320:*
SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT:321:*
+SSL_F_SSL_SENDFILE:639:SSL_sendfile
SSL_F_SSL_SESSION_DUP:348:ssl_session_dup
SSL_F_SSL_SESSION_NEW:189:SSL_SESSION_new
SSL_F_SSL_SESSION_PRINT_FP:190:SSL_SESSION_print_fp
diff --git a/doc/man3/SSL_write.pod b/doc/man3/SSL_write.pod
index a73bc06..b18c215 100644
--- a/doc/man3/SSL_write.pod
+++ b/doc/man3/SSL_write.pod
@@ -2,12 +2,13 @@
=head1 NAME
-SSL_write_ex, SSL_write - write bytes to a TLS/SSL connection
+SSL_write_ex, SSL_write, SSL_sendfile - write bytes to a TLS/SSL connection
=head1 SYNOPSIS
#include <openssl/ssl.h>
+ ossl_ssize_t SSL_sendfile(SSL *s, int fd, off_t offset, size_t size, int flags);
int SSL_write_ex(SSL *s, const void *buf, size_t num, size_t *written);
int SSL_write(SSL *ssl, const void *buf, int num);
@@ -17,6 +18,14 @@ SSL_write_ex() and SSL_write() write B<num> bytes from the buffer B<buf> into
the specified B<ssl> connection. On success SSL_write_ex() will store the number
of bytes written in B<*written>.
+SSL_sendfile() writes B<size> bytes from offset B<offset> in the file
+descriptor B<fd> to the specified SSL connection B<s>. This function provides
+efficient zero-copy semantics. SSL_sendfile() is available only when
+Kernel TLS is enabled, which can be checked by calling BIO_get_ktls_send().
+It is provided here to allow users to maintain the same interface.
+The meaning of B<flags> is platform dependent.
+Currently, under Linux it is ignored.
+
=head1 NOTES
In the paragraphs below a "write function" is defined as one of either
@@ -104,17 +113,35 @@ You should instead call SSL_get_error() to find out if it's retryable.
=back
+For SSL_sendfile(), the following return values can occur:
+
+=over 4
+
+=item Z<>>= 0
+
+The write operation was successful, the return value is the number
+of bytes of the file written to the TLS/SSL connection.
+
+=item E<lt> 0
+
+The write operation was not successful, because either the connection was
+closed, an error occured or action must be taken by the calling process.
+Call SSL_get_error() with the return value to find out the reason.
+
+=back
+
=head1 SEE ALSO
L<SSL_get_error(3)>, L<SSL_read_ex(3)>, L<SSL_read(3)>
L<SSL_CTX_set_mode(3)>, L<SSL_CTX_new(3)>,
L<SSL_connect(3)>, L<SSL_accept(3)>
-L<SSL_set_connect_state(3)>,
+L<SSL_set_connect_state(3)>, L<BIO_ctrl(3)>,
L<ssl(7)>, L<bio(7)>
=head1 HISTORY
The SSL_write_ex() function was added in OpenSSL 1.1.1.
+The SSL_sendfile() function was added in OpenSSL 3.0.0.
=head1 COPYRIGHT
diff --git a/include/internal/ktls.h b/include/internal/ktls.h
index d7bd1f3..9f2af12 100644
--- a/include/internal/ktls.h
+++ b/include/internal/ktls.h
@@ -73,8 +73,14 @@ static ossl_inline int ktls_read_record(int fd, void *data, size_t length)
return -1;
}
+static ossl_inline ossl_ssize_t ktls_sendfile(int s, int fd, off_t off, size_t size, int flags)
+{
+ return -1;
+}
+
# else /* KERNEL_VERSION */
+# include <sys/sendfile.h>
# include <netinet/tcp.h>
# include <linux/tls.h>
# include <linux/socket.h>
@@ -158,6 +164,15 @@ static ossl_inline int ktls_send_ctrl_message(int fd, unsigned char record_type,
return sendmsg(fd, &msg, 0);
}
+/*
+ * KTLS enables the sendfile system call to send data from a file over TLS.
+ * @flags are ignored on Linux. (placeholder for FreeBSD sendfile)
+ * */
+static ossl_inline ossl_ssize_t ktls_sendfile(int s, int fd, off_t off, size_t size, int flags)
+{
+ return sendfile(s, fd, &off, size);
+}
+
# define K_MIN1_RX 17
# if LINUX_VERSION_CODE < KERNEL_VERSION(K_MAJ, K_MIN1_RX, K_MIN2)
diff --git a/include/openssl/err.h b/include/openssl/err.h
index 8fcdfb4..7398029 100644
--- a/include/openssl/err.h
+++ b/include/openssl/err.h
@@ -177,6 +177,7 @@ typedef struct err_state_st {
# define SYS_F_STAT 22
# define SYS_F_FCNTL 23
# define SYS_F_FSTAT 24
+# define SYS_F_SENDFILE 25
/* reasons */
# define ERR_R_SYS_LIB ERR_LIB_SYS/* 2 */
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index f4b17f1..60712d0 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -1848,6 +1848,8 @@ __owur int SSL_read_early_data(SSL *s, void *buf, size_t num,
size_t *readbytes);
__owur int SSL_peek(SSL *ssl, void *buf, int num);
__owur int SSL_peek_ex(SSL *ssl, void *buf, size_t num, size_t *readbytes);
+__owur ossl_ssize_t SSL_sendfile(SSL *s, int fd, off_t offset, size_t size,
+ int flags);
__owur int SSL_write(SSL *ssl, const void *buf, int num);
__owur int SSL_write_ex(SSL *s, const void *buf, size_t num, size_t *written);
__owur int SSL_write_early_data(SSL *s, const void *buf, size_t num,
diff --git a/include/openssl/sslerr.h b/include/openssl/sslerr.h
index 7f776f9..385fda3 100644
--- a/include/openssl/sslerr.h
+++ b/include/openssl/sslerr.h
@@ -217,6 +217,7 @@ int ERR_load_SSL_strings(void);
# define SSL_F_SSL_RENEGOTIATE_ABBREVIATED 546
# define SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT 320
# define SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT 321
+# define SSL_F_SSL_SENDFILE 639
# define SSL_F_SSL_SESSION_DUP 348
# define SSL_F_SSL_SESSION_NEW 189
# define SSL_F_SSL_SESSION_PRINT_FP 190
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index afe1b58..daeee1e 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -311,6 +311,7 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
"SSL_renegotiate_abbreviated"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT, 0), ""},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, 0), ""},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SENDFILE, 0), "SSL_sendfile"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_DUP, 0), "ssl_session_dup"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_NEW, 0), "SSL_SESSION_new"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_PRINT_FP, 0),
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 89a4100..910f82b 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -11,6 +11,7 @@
#include <stdio.h>
#include "ssl_locl.h"
+#include "e_os.h"
#include <openssl/objects.h>
#include <openssl/x509v3.h>
#include <openssl/rand.h>
@@ -2008,6 +2009,72 @@ int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written)
}
}
+ossl_ssize_t SSL_sendfile(SSL *s, int fd, off_t offset, size_t size, int flags)
+{
+ ossl_ssize_t ret;
+
+ if (s->handshake_func == NULL) {
+ SSLerr(SSL_F_SSL_SENDFILE, SSL_R_UNINITIALIZED);
+ return -1;
+ }
+
+ if (s->shutdown & SSL_SENT_SHUTDOWN) {
+ s->rwstate = SSL_NOTHING;
+ SSLerr(SSL_F_SSL_SENDFILE, SSL_R_PROTOCOL_IS_SHUTDOWN);
+ return -1;
+ }
+
+ if (!BIO_get_ktls_send(s->wbio)) {
+ SSLerr(SSL_F_SSL_SENDFILE, SSL_R_UNINITIALIZED);
+ return -1;
+ }
+
+ /* If we have an alert to send, lets send it */
+ if (s->s3.alert_dispatch) {
+ ret = (ossl_ssize_t)s->method->ssl_dispatch_alert(s);
+ if (ret <= 0) {
+ /* SSLfatal() already called if appropriate */
+ return ret;
+ }
+ /* if it went, fall through and send more stuff */
+ }
+
+ s->rwstate = SSL_WRITING;
+ if (BIO_flush(s->wbio) <= 0) {
+ if (!BIO_should_retry(s->wbio)) {
+ s->rwstate = SSL_NOTHING;
+ } else {
+#ifdef EAGAIN
+ set_sys_error(EAGAIN);
+#endif
+ }
+ return -1;
+ }
+
+#ifndef OPENSSL_NO_KTLS
+ ret = ktls_sendfile(SSL_get_wfd(s), fd, offset, size, flags);
+#else
+ ret = -1;
+#endif
+ if (ret < 0) {
+#if defined(EAGAIN) && defined(EINTR) && defined(EBUSY)
+ if ((get_last_sys_error() == EAGAIN) ||
+ (get_last_sys_error() == EINTR) ||
+ (get_last_sys_error() == EBUSY))
+ BIO_set_retry_write(s->wbio);
+ else
+#endif
+#ifdef OPENSSL_NO_KTLS
+ SYSerr(SYS_F_SENDFILE, get_last_sys_error());
+#else
+ SSLerr(SSL_F_SSL_SENDFILE, SSL_R_UNINITIALIZED);
+#endif
+ return ret;
+ }
+ s->rwstate = SSL_NOTHING;
+ return ret;
+}
+
int SSL_write(SSL *s, const void *buf, int num)
{
int ret;
diff --git a/test/sslapitest.c b/test/sslapitest.c
index 7ca8c75..3504eea 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -7,6 +7,7 @@
* https://www.openssl.org/source/license.html
*/
+#include <stdio.h>
#include <string.h>
#include <openssl/opensslconf.h>
@@ -17,6 +18,7 @@
#include <openssl/srp.h>
#include <openssl/txt_db.h>
#include <openssl/aes.h>
+#include <openssl/rand.h>
#include "ssltestlib.h"
#include "testutil.h"
@@ -918,6 +920,111 @@ end:
return testresult;
}
+#define SENDFILE_SZ (16 * 4096)
+#define SENDFILE_CHUNK (4 * 4096)
+#define min(a,b) ((a) > (b) ? (b) : (a))
+
+static int test_ktls_sendfile(void)
+{
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ unsigned char *buf, *buf_dst;
+ BIO *out = NULL, *in = NULL;
+ int cfd, sfd, ffd, err;
+ ssize_t chunk_size = 0;
+ off_t chunk_off = 0;
+ int testresult = 0;
+ FILE *ffdp;
+
+ buf = OPENSSL_zalloc(SENDFILE_SZ);
+ buf_dst = OPENSSL_zalloc(SENDFILE_SZ);
+ if (!TEST_ptr(buf) || !TEST_ptr(buf_dst)
+ || !TEST_true(create_test_sockets(&cfd, &sfd)))
+ goto end;
+
+ /* Skip this test if the platform does not support ktls */
+ if (!ktls_chk_platform(sfd)) {
+ testresult = 1;
+ goto end;
+ }
+
+ /* Create a session based on SHA-256 */
+ if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(),
+ TLS_client_method(),
+ TLS1_2_VERSION, TLS1_2_VERSION,
+ &sctx, &cctx, cert, privkey))
+ || !TEST_true(SSL_CTX_set_cipher_list(cctx,
+ "AES128-GCM-SHA256"))
+ || !TEST_true(create_ssl_objects2(sctx, cctx, &serverssl,
+ &clientssl, sfd, cfd)))
+ goto end;
+
+ if (!TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE))
+ || !TEST_true(BIO_get_ktls_send(serverssl->wbio)))
+ goto end;
+
+ RAND_bytes(buf, SENDFILE_SZ);
+ out = BIO_new_file(tmpfilename, "wb");
+ if (!TEST_ptr(out))
+ goto end;
+
+ if (BIO_write(out, buf, SENDFILE_SZ) != SENDFILE_SZ)
+ goto end;
+
+ BIO_free(out);
+ out = NULL;
+ in = BIO_new_file(tmpfilename, "rb");
+ BIO_get_fp(in, &ffdp);
+ ffd = fileno(ffdp);
+
+ while (chunk_off < SENDFILE_SZ) {
+ chunk_size = min(SENDFILE_CHUNK, SENDFILE_SZ - chunk_off);
+ while ((err = SSL_sendfile(serverssl,
+ ffd,
+ chunk_off,
+ chunk_size,
+ 0)) != chunk_size) {
+ if (SSL_get_error(serverssl, err) != SSL_ERROR_WANT_WRITE)
+ goto end;
+ }
+ while ((err = SSL_read(clientssl,
+ buf_dst + chunk_off,
+ chunk_size)) != chunk_size) {
+ if (SSL_get_error(clientssl, err) != SSL_ERROR_WANT_READ)
+ goto end;
+ }
+
+ /* verify the payload */
+ if (!TEST_mem_eq(buf_dst + chunk_off,
+ chunk_size,
+ buf + chunk_off,
+ chunk_size))
+ goto end;
+
+ chunk_off += chunk_size;
+ }
+
+ testresult = 1;
+end:
+ if (clientssl) {
+ SSL_shutdown(clientssl);
+ SSL_free(clientssl);
+ }
+ if (serverssl) {
+ SSL_shutdown(serverssl);
+ SSL_free(serverssl);
+ }
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+ serverssl = clientssl = NULL;
+ BIO_free(out);
+ BIO_free(in);
+ OPENSSL_free(buf);
+ OPENSSL_free(buf_dst);
+ return testresult;
+}
+
static int test_ktls_no_txrx_client_no_txrx_server(void)
{
return execute_test_ktls(0, 0, 0, 0);
@@ -997,7 +1104,6 @@ static int test_ktls_client_server(void)
{
return execute_test_ktls(1, 1, 1, 1);
}
-
#endif
static int test_large_message_tls(void)
@@ -6280,6 +6386,7 @@ int setup_tests(void)
ADD_TEST(test_ktls_no_rx_client_server);
ADD_TEST(test_ktls_no_tx_client_server);
ADD_TEST(test_ktls_client_server);
+ ADD_TEST(test_ktls_sendfile);
#endif
ADD_TEST(test_large_message_tls);
ADD_TEST(test_large_message_tls_read_ahead);
diff --git a/util/libssl.num b/util/libssl.num
index d59ccf9..c34200f 100644
--- a/util/libssl.num
+++ b/util/libssl.num
@@ -503,3 +503,4 @@ SSL_CTX_set_async_callback_arg 503 3_0_0 EXIST::FUNCTION:
SSL_set_async_callback 504 3_0_0 EXIST::FUNCTION:
SSL_set_async_callback_arg 505 3_0_0 EXIST::FUNCTION:
SSL_get_async_status 506 3_0_0 EXIST::FUNCTION:
+SSL_sendfile 507 3_0_0 EXIST::FUNCTION:
More information about the openssl-commits
mailing list