Add the OSSL_PROVIDER_get_capabilities() API function
[openssl.git] / include / internal / ktls.h
index 9f2af1200c922b4fb0be4838995af42a30f196ed..093a6618438670b6c03928db2fab0dde0dd6ce29 100644 (file)
@@ -7,65 +7,93 @@
  * https://www.openssl.org/source/license.html
  */
 
+#if defined(OPENSSL_SYS_LINUX)
+# ifndef OPENSSL_NO_KTLS
+#  include <linux/version.h>
+#  if LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0)
+#   define OPENSSL_NO_KTLS
+#   ifndef PEDANTIC
+#    warning "KTLS requires Kernel Headers >= 4.13.0"
+#    warning "Skipping Compilation of KTLS"
+#   endif
+#  endif
+# endif
+#endif
+
 #ifndef OPENSSL_NO_KTLS
 # ifndef HEADER_INTERNAL_KTLS
 #  define HEADER_INTERNAL_KTLS
 
-#  if defined(OPENSSL_SYS_LINUX)
-#   include <linux/version.h>
-
-#   define K_MAJ   4
-#   define K_MIN1  13
-#   define K_MIN2  0
-#   if LINUX_VERSION_CODE < KERNEL_VERSION(K_MAJ, K_MIN1, K_MIN2)
-
-#    ifndef PEDANTIC
-#     warning "KTLS requires Kernel Headers >= 4.13.0"
-#     warning "Skipping Compilation of KTLS"
-#    endif
-
-#    define TLS_TX                  1
-#    define TLS_RX                  2
-
-#    define TLS_CIPHER_AES_GCM_128                          51
-#    define TLS_CIPHER_AES_GCM_128_IV_SIZE                  8
-#    define TLS_CIPHER_AES_GCM_128_KEY_SIZE                 16
-#    define TLS_CIPHER_AES_GCM_128_SALT_SIZE                4
-#    define TLS_CIPHER_AES_GCM_128_TAG_SIZE                 16
-#    define TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE             8
-
-#    define TLS_SET_RECORD_TYPE     1
-
-struct tls_crypto_info {
-    unsigned short version;
-    unsigned short cipher_type;
-};
+#  if defined(__FreeBSD__)
+#   include <sys/types.h>
+#   include <sys/socket.h>
+#   include <sys/ktls.h>
+#   include <netinet/in.h>
+#   include <netinet/tcp.h>
+#   include <crypto/cryptodev.h>
 
-struct tls12_crypto_info_aes_gcm_128 {
-    struct tls_crypto_info info;
-    unsigned char iv[TLS_CIPHER_AES_GCM_128_IV_SIZE];
-    unsigned char key[TLS_CIPHER_AES_GCM_128_KEY_SIZE];
-    unsigned char salt[TLS_CIPHER_AES_GCM_128_SALT_SIZE];
-    unsigned char rec_seq[TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE];
-};
+/*
+ * Only used by the tests in sslapitest.c.
+ */
+#   define TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE             8
 
-/* Dummy functions here */
+/*
+ * FreeBSD does not require any additional steps to enable KTLS before
+ * setting keys.
+ */
 static ossl_inline int ktls_enable(int fd)
 {
-    return 0;
+    return 1;
 }
 
+/*
+ * The TCP_TXTLS_ENABLE socket option marks the outgoing socket buffer
+ * as using TLS.  If successful, then data sent using this socket will
+ * be encrypted and encapsulated in TLS records using the tls_en.
+ * provided here.
+ */
 static ossl_inline int ktls_start(int fd,
-                                  struct tls12_crypto_info_aes_gcm_128
-                                  *crypto_info, size_t len, int is_tx)
+                                  void *tls_en,
+                                  size_t len, int is_tx)
 {
-    return 0;
+    if (is_tx)
+        return setsockopt(fd, IPPROTO_TCP, TCP_TXTLS_ENABLE,
+                          tls_en, len) ? 0 : 1;
+    else
+        return 0;
 }
 
+/*
+ * Send a TLS record using the tls_en provided in ktls_start and use
+ * record_type instead of the default SSL3_RT_APPLICATION_DATA.
+ * When the socket is non-blocking, then this call either returns EAGAIN or
+ * the entire record is pushed to TCP. It is impossible to send a partial
+ * record using this control message.
+ */
 static ossl_inline int ktls_send_ctrl_message(int fd, unsigned char record_type,
                                               const void *data, size_t length)
 {
-    return -1;
+    struct msghdr msg = { 0 };
+    int cmsg_len = sizeof(record_type);
+    struct cmsghdr *cmsg;
+    char buf[CMSG_SPACE(cmsg_len)];
+    struct iovec msg_iov;   /* Vector of data to send/receive into */
+
+    msg.msg_control = buf;
+    msg.msg_controllen = sizeof(buf);
+    cmsg = CMSG_FIRSTHDR(&msg);
+    cmsg->cmsg_level = IPPROTO_TCP;
+    cmsg->cmsg_type = TLS_SET_RECORD_TYPE;
+    cmsg->cmsg_len = CMSG_LEN(cmsg_len);
+    *((unsigned char *)CMSG_DATA(cmsg)) = record_type;
+    msg.msg_controllen = cmsg->cmsg_len;
+
+    msg_iov.iov_base = (void *)data;
+    msg_iov.iov_len = length;
+    msg.msg_iov = &msg_iov;
+    msg.msg_iovlen = 1;
+
+    return sendmsg(fd, &msg, 0);
 }
 
 static ossl_inline int ktls_read_record(int fd, void *data, size_t length)
@@ -73,33 +101,78 @@ 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)
+/*
+ * KTLS enables the sendfile system call to send data from a file over
+ * TLS.
+ */
+static ossl_inline ossl_ssize_t ktls_sendfile(int s, int fd, off_t off,
+                                              size_t size, int flags)
 {
-    return -1;
-}
+    off_t sbytes;
+    int ret;
 
-#   else                        /* KERNEL_VERSION */
+    ret = sendfile(fd, s, off, size, NULL, &sbytes, flags);
+    if (ret == -1) {
+           if (errno == EAGAIN && sbytes != 0)
+                   return sbytes;
+           return -1;
+    }
+    return sbytes;
+}
+#  endif                         /* __FreeBSD__ */
 
-#    include <sys/sendfile.h>
-#    include <netinet/tcp.h>
-#    include <linux/tls.h>
-#    include <linux/socket.h>
-#    include "openssl/ssl3.h"
-#    include "openssl/tls1.h"
-#    include "openssl/evp.h"
+#  if defined(OPENSSL_SYS_LINUX)
 
-#    ifndef SOL_TLS
-#     define SOL_TLS 282
+#   include <linux/tls.h>
+#   if LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)
+#    define OPENSSL_NO_KTLS_RX
+#    ifndef PEDANTIC
+#     warning "KTLS requires Kernel Headers >= 4.17.0 for receiving"
+#     warning "Skipping Compilation of KTLS receive data path"
 #    endif
-
-#    ifndef TCP_ULP
-#     define TCP_ULP 31
+#   endif
+#   define OPENSSL_KTLS_AES_GCM_128
+#   if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
+#    define OPENSSL_KTLS_AES_GCM_256
+#    define OPENSSL_KTLS_TLS13
+#    if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)
+#     define OPENSSL_KTLS_AES_CCM_128
 #    endif
+#   endif
 
-#    ifndef TLS_RX
-#     define TLS_RX                  2
-#    endif
+#   include <sys/sendfile.h>
+#   include <netinet/tcp.h>
+#   include <linux/socket.h>
+#   include "openssl/ssl3.h"
+#   include "openssl/tls1.h"
+#   include "openssl/evp.h"
+
+#   ifndef SOL_TLS
+#    define SOL_TLS 282
+#   endif
 
+#   ifndef TCP_ULP
+#    define TCP_ULP 31
+#   endif
+
+#   ifndef TLS_RX
+#    define TLS_RX                  2
+#   endif
+
+struct tls_crypto_info_all {
+    union {
+#   ifdef OPENSSL_KTLS_AES_GCM_128
+        struct tls12_crypto_info_aes_gcm_128 gcm128;
+#   endif
+#   ifdef OPENSSL_KTLS_AES_GCM_256
+        struct tls12_crypto_info_aes_gcm_256 gcm256;
+#   endif
+#   ifdef OPENSSL_KTLS_AES_CCM_128
+        struct tls12_crypto_info_aes_ccm_128 ccm128;
+#   endif
+    };
+    size_t tls_crypto_info_len;
+};
 /*
  * When successful, this socket option doesn't change the behaviour of the
  * TCP socket, except changing the TCP setsockopt handler to enable the
@@ -119,12 +192,11 @@ static ossl_inline int ktls_enable(int fd)
  * If successful, then data received using this socket will be decrypted,
  * authenticated and decapsulated using the crypto_info provided here.
  */
-static ossl_inline int ktls_start(int fd,
-                                  struct tls12_crypto_info_aes_gcm_128
-                                  *crypto_info, size_t len, int is_tx)
+static ossl_inline int ktls_start(int fd, void *crypto_info,
+                                  size_t len, int is_tx)
 {
     return setsockopt(fd, SOL_TLS, is_tx ? TLS_TX : TLS_RX,
-                      crypto_info, sizeof(*crypto_info)) ? 0 : 1;
+                      crypto_info, len) ? 0 : 1;
 }
 
 /*
@@ -173,20 +245,15 @@ static ossl_inline ossl_ssize_t ktls_sendfile(int s, int fd, off_t off, size_t s
     return sendfile(s, fd, &off, size);
 }
 
-#    define K_MIN1_RX  17
-#    if LINUX_VERSION_CODE < KERNEL_VERSION(K_MAJ, K_MIN1_RX, K_MIN2)
+#   ifdef OPENSSL_NO_KTLS_RX
 
-#     ifndef PEDANTIC
-#      warning "KTLS requires Kernel Headers >= 4.17.0 for receiving"
-#      warning "Skipping Compilation of KTLS receive data path"
-#     endif
 
 static ossl_inline int ktls_read_record(int fd, void *data, size_t length)
 {
     return -1;
 }
 
-#    else
+#   else /* !defined(OPENSSL_NO_KTLS_RX) */
 
 /*
  * Receive a TLS record using the crypto_info provided in ktls_start.
@@ -241,8 +308,132 @@ static ossl_inline int ktls_read_record(int fd, void *data, size_t length)
     return ret;
 }
 
-#    endif
-#   endif
+#   endif /* OPENSSL_NO_KTLS_RX */
+
+/* Function to check supported ciphers in Linux */
+static ossl_inline int ktls_check_supported_cipher(const EVP_CIPHER *c,
+                                            const EVP_CIPHER_CTX *dd)
+{
+    /* check that cipher is AES_GCM_128, AES_GCM_256, AES_CCM_128 */
+    switch (EVP_CIPHER_nid(c))
+    {
+#  ifdef OPENSSL_KTLS_AES_CCM_128
+    case NID_aes_128_ccm:
+        if (EVP_CIPHER_CTX_tag_length(dd) != EVP_CCM_TLS_TAG_LEN)
+          return 0;
 #  endif
-# endif
+#  ifdef OPENSSL_KTLS_AES_GCM_128
+    case NID_aes_128_gcm:
+#  endif
+#  ifdef OPENSSL_KTLS_AES_GCM_256
+    case NID_aes_256_gcm:
+#  endif
+        return 1;
+    default:
+        return 0;
+    }
+}
+
+/* Function to configure kernel TLS structure */
+static ossl_inline int ktls_configure_crypto(const EVP_CIPHER *c, int tls_version,
+                                EVP_CIPHER_CTX *dd, void *rl_sequence,
+                                struct tls_crypto_info_all *crypto_info,
+                                unsigned char **rec_seq, unsigned char *iv,
+                                unsigned char *key)
+{
+    unsigned char geniv[12];
+    unsigned char *iiv = iv;
+
+    if (tls_version == TLS1_2_VERSION &&
+        EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE) {
+        EVP_CIPHER_CTX_ctrl(dd, EVP_CTRL_GET_IV,
+                            EVP_GCM_TLS_FIXED_IV_LEN + EVP_GCM_TLS_EXPLICIT_IV_LEN,
+                            geniv);
+        iiv = geniv;
+    }
+
+    memset(crypto_info, 0, sizeof(*crypto_info));
+    switch (EVP_CIPHER_nid(c))
+    {
+#  ifdef OPENSSL_KTLS_AES_GCM_128
+    case NID_aes_128_gcm:
+        crypto_info->gcm128.info.cipher_type = TLS_CIPHER_AES_GCM_128;
+        crypto_info->gcm128.info.version = tls_version;
+        crypto_info->tls_crypto_info_len = sizeof(crypto_info->gcm128);
+        memcpy(crypto_info->gcm128.iv, iiv + EVP_GCM_TLS_FIXED_IV_LEN,
+                TLS_CIPHER_AES_GCM_128_IV_SIZE);
+        memcpy(crypto_info->gcm128.salt, iiv, TLS_CIPHER_AES_GCM_128_SALT_SIZE);
+        memcpy(crypto_info->gcm128.key, key, EVP_CIPHER_key_length(c));
+        memcpy(crypto_info->gcm128.rec_seq, rl_sequence,
+                TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
+        if (rec_seq != NULL)
+            *rec_seq = crypto_info->gcm128.rec_seq;
+        return 1;
+#  endif
+#  ifdef OPENSSL_KTLS_AES_GCM_256
+    case NID_aes_256_gcm:
+        crypto_info->gcm256.info.cipher_type = TLS_CIPHER_AES_GCM_256;
+        crypto_info->gcm256.info.version = tls_version;
+        crypto_info->tls_crypto_info_len = sizeof(crypto_info->gcm256);
+        memcpy(crypto_info->gcm256.iv, iiv + EVP_GCM_TLS_FIXED_IV_LEN,
+                TLS_CIPHER_AES_GCM_256_IV_SIZE);
+        memcpy(crypto_info->gcm256.salt, iiv, TLS_CIPHER_AES_GCM_256_SALT_SIZE);
+        memcpy(crypto_info->gcm256.key, key, EVP_CIPHER_key_length(c));
+        memcpy(crypto_info->gcm256.rec_seq, rl_sequence,
+                TLS_CIPHER_AES_GCM_256_REC_SEQ_SIZE);
+        if (rec_seq != NULL)
+            *rec_seq = crypto_info->gcm256.rec_seq;
+        return 1;
+#  endif
+#  ifdef OPENSSL_KTLS_AES_CCM_128
+    case NID_aes_128_ccm:
+        crypto_info->ccm128.info.cipher_type = TLS_CIPHER_AES_CCM_128;
+        crypto_info->ccm128.info.version = tls_version;
+        crypto_info->tls_crypto_info_len = sizeof(crypto_info->ccm128);
+        memcpy(crypto_info->ccm128.iv, iiv + EVP_CCM_TLS_FIXED_IV_LEN,
+                TLS_CIPHER_AES_CCM_128_IV_SIZE);
+        memcpy(crypto_info->ccm128.salt, iiv, TLS_CIPHER_AES_CCM_128_SALT_SIZE);
+        memcpy(crypto_info->ccm128.key, key, EVP_CIPHER_key_length(c));
+        memcpy(crypto_info->ccm128.rec_seq, rl_sequence,
+                TLS_CIPHER_AES_CCM_128_REC_SEQ_SIZE);
+        if (rec_seq != NULL)
+            *rec_seq = crypto_info->ccm128.rec_seq;
+        return 1;
+#  endif
+    default:
+        return 0;
+    }
+
+}
+
+#  endif /* OPENSSL_SYS_LINUX */
+# endif /* HEADER_INTERNAL_KTLS */
+#else /* defined(OPENSSL_NO_KTLS) */
+/* Dummy functions here */
+static ossl_inline int ktls_enable(int fd)
+{
+    return 0;
+}
+
+static ossl_inline int ktls_start(int fd, void *crypto_info,
+                                  size_t len, int is_tx)
+{
+    return 0;
+}
+
+static ossl_inline int ktls_send_ctrl_message(int fd, unsigned char record_type,
+                                              const void *data, size_t length)
+{
+    return -1;
+}
+
+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;
+}
 #endif