summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2018-06-14 19:38:38 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2018-06-14 19:38:38 +0000
commitb4385d3c28ef16c3b9cbd6a3933e04826ca34aab (patch)
tree8cf0b33ce196e49945606baef98499b296e732c6
parentcc5c1553d44b68f99e58d13f988fff16ef4ab460 (diff)
parent8d63246c1a93e18701c63e3d69f9e5ea476b8703 (diff)
downloadgnutls-b4385d3c28ef16c3b9cbd6a3933e04826ca34aab.tar.gz
Merge branch 'tmp-iovec-api' into 'master'
Introduce an iovec API for encryption Closes #458 See merge request gnutls/gnutls!653
-rw-r--r--Makefile.am4
-rw-r--r--configure.ac2
-rw-r--r--doc/Makefile.am2
-rw-r--r--doc/cha-crypto.texi32
-rw-r--r--doc/manpages/Makefile.am1
-rw-r--r--lib/cipher.c73
-rw-r--r--lib/crypto-api.c249
-rw-r--r--lib/crypto-selftests.c194
-rw-r--r--lib/gnutls_int.h2
-rw-r--r--lib/includes/gnutls/crypto.h8
-rw-r--r--lib/libgnutls.map1
-rw-r--r--src/benchmark-tls.c34
-rw-r--r--symbols.last1
13 files changed, 550 insertions, 53 deletions
diff --git a/Makefile.am b/Makefile.am
index 34ea4b5e0f..0f7c8a29a8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -83,6 +83,9 @@ ABIVER=$(shell git for-each-ref --sort=taggerdate --format '%(refname)' refs/tag
fi && $(MAKE) -j$$(nproc) -C gl && $(MAKE) -j$$(nproc) -C lib && $(MAKE) -j$$(nproc) -C libdane
touch $@
+# We skip session::set_transport_vec_push_function() as it is seen as different when
+# compiled with the glibc struct iovec, under gcc8. This should be temporary for
+# 3.6.2 to 3.6.3 transition.
abi-check: .prev-tag-abi.stamp
@rm -f $(ABI_TMPFILE_CUR) $(ABI_TMPFILE_PRE)
@echo "Checking libgnutls ABI"
@@ -93,6 +96,7 @@ abi-check: .prev-tag-abi.stamp
@echo "<version>$(VERSION)</version>" >$(ABI_TMPFILE_PRE)
@echo "<headers>$(builddir)/$(ABI_TMPCLONEDIR)/lib/includes/gnutls" >>$(ABI_TMPFILE_PRE)
@echo "$(builddir)/$(ABI_TMPCLONEDIR)/lib/includes/gnutls</headers>" >>$(ABI_TMPFILE_PRE)
+ @echo "<skip_symbols>_ZN6gnutls7session31set_transport_vec_push_functionEPFlPvPK8giovec_tiE</skip_symbols>" >>$(ABI_TMPFILE_PRE)
@echo "<libs>$(builddir)/$(ABI_TMPCLONEDIR)/lib/.libs</libs>" >>$(ABI_TMPFILE_PRE)
PATH="/sbin$(PATH_SEPARATOR)$$PATH" \
abi-compliance-checker -abi -lib gnutls -old $(ABI_TMPFILE_PRE) -new $(ABI_TMPFILE_CUR) -skip-symbols $(srcdir)/devel/abi-unchecked-symbols
diff --git a/configure.ac b/configure.ac
index f7a07d382d..cf76246c58 100644
--- a/configure.ac
+++ b/configure.ac
@@ -180,7 +180,7 @@ esac
fi
dnl Check for iovec type
-AC_CHECK_MEMBERS([struct iovec.iov_basea],
+AC_CHECK_MEMBERS([struct iovec.iov_base],
[
AC_SUBST([DEFINE_IOVEC_T], ["#include <sys/uio.h>
typedef struct iovec giovec_t;"])
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 73097bcea4..e35e92ffd0 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -637,6 +637,8 @@ FUNCS += functions/gnutls_aead_cipher_deinit
FUNCS += functions/gnutls_aead_cipher_deinit.short
FUNCS += functions/gnutls_aead_cipher_encrypt
FUNCS += functions/gnutls_aead_cipher_encrypt.short
+FUNCS += functions/gnutls_aead_cipher_encryptv
+FUNCS += functions/gnutls_aead_cipher_encryptv.short
FUNCS += functions/gnutls_aead_cipher_init
FUNCS += functions/gnutls_aead_cipher_init.short
FUNCS += functions/gnutls_alert_get
diff --git a/doc/cha-crypto.texi b/doc/cha-crypto.texi
index dc28a42a94..ab5f9ac15f 100644
--- a/doc/cha-crypto.texi
+++ b/doc/cha-crypto.texi
@@ -23,11 +23,37 @@ to the random number generation. For a low-level crypto API the usage of nettle
@cindex symmetric cryptography
The available functions to access symmetric crypto algorithms operations
-are shown below. The supported algorithms are the algorithms required by the TLS protocol.
-They are listed in @ref{gnutls_cipher_algorithm_t}.
+are listed in the sections below. The supported algorithms are the algorithms required by the TLS protocol.
+They are listed in @ref{gnutls_cipher_algorithm_t}. Note that there two
+types of ciphers, the ones providing an authenticated-encryption with
+associated data (AEAD), and the legacy ciphers which provide raw access
+to the ciphers. We recommend the use of the AEAD APIs for new applications
+as it is designed to minimize misuse of cryptography.
@showenumdesc{gnutls_cipher_algorithm_t,The supported ciphers.}
+@subheading Authenticated-encryption API
+
+The AEAD API provides access to all ciphers supported by GnuTLS which support
+authenticated encryption with associated data. That is particularly suitable
+for message or packet-encryption as it provides authentication and
+encryption on the same API. See @code{RFC5116} for more information on
+authenticated encryption.
+
+@showfuncD{gnutls_aead_cipher_init,gnutls_aead_cipher_encrypt,gnutls_aead_cipher_decrypt,gnutls_aead_cipher_deinit}
+
+Because the encryption function above may be difficult to use with
+scattered data, we provide the following API.
+
+@showfuncdesc{gnutls_aead_cipher_encryptv}
+
+@subheading Legacy API
+
+The legacy API provides low-level access to all legacy ciphers supported by GnuTLS,
+and some of the AEAD ciphers (e.g., AES-GCM and CHACHA20). The restrictions
+of the nettle library implementation of the ciphers apply verbatim to this
+API@footnote{See the nettle manual @url{https://www.lysator.liu.se/~nisse/nettle/nettle.html}}.
+
@showfuncE{gnutls_cipher_init,gnutls_cipher_encrypt2,gnutls_cipher_decrypt2,gnutls_cipher_set_iv,gnutls_cipher_deinit}
@showfuncB{gnutls_cipher_add_auth,gnutls_cipher_tag}
@@ -36,8 +62,6 @@ it is recommended to use the following functions which are solely for AEAD ciphe
API is designed to be simple to use and also hard to misuse, by handling the tag verification
and addition in transparent way.
-@showfuncD{gnutls_aead_cipher_init,gnutls_aead_cipher_encrypt,gnutls_aead_cipher_decrypt,gnutls_aead_cipher_deinit}
-
@node Public key algorithms
@section Public key algorithms
@cindex public key algorithms
diff --git a/doc/manpages/Makefile.am b/doc/manpages/Makefile.am
index b1082f8386..66e92efa4b 100644
--- a/doc/manpages/Makefile.am
+++ b/doc/manpages/Makefile.am
@@ -114,6 +114,7 @@ APIMANS += dane_verify_session_crt.3
APIMANS += gnutls_aead_cipher_decrypt.3
APIMANS += gnutls_aead_cipher_deinit.3
APIMANS += gnutls_aead_cipher_encrypt.3
+APIMANS += gnutls_aead_cipher_encryptv.3
APIMANS += gnutls_aead_cipher_init.3
APIMANS += gnutls_alert_get.3
APIMANS += gnutls_alert_get_name.3
diff --git a/lib/cipher.c b/lib/cipher.c
index 2bfae68552..a502a16986 100644
--- a/lib/cipher.c
+++ b/lib/cipher.c
@@ -67,8 +67,8 @@ static int
encrypt_packet_tls13(gnutls_session_t session,
uint8_t *cipher_data, size_t cipher_size,
gnutls_datum_t *plain,
- size_t min_pad,
- content_type_t type,
+ size_t pad_size,
+ uint8_t type,
record_parameters_st *params);
/* returns ciphertext which contains the headers too. This also
@@ -417,8 +417,8 @@ static int
encrypt_packet_tls13(gnutls_session_t session,
uint8_t *cipher_data, size_t cipher_size,
gnutls_datum_t *plain,
- size_t min_pad,
- content_type_t type,
+ size_t pad_size,
+ uint8_t type,
record_parameters_st *params)
{
int ret;
@@ -426,9 +426,10 @@ encrypt_packet_tls13(gnutls_session_t session,
const version_entry_st *ver = get_version(session);
uint8_t nonce[MAX_CIPHER_IV_SIZE];
unsigned iv_size = 0;
- uint8_t *fdata;
- ssize_t fdata_size, max;
+ ssize_t max, total;
uint8_t aad[5];
+ giovec_t auth_iov[1];
+ giovec_t iov[2];
if (unlikely(ver == NULL))
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
@@ -453,39 +454,57 @@ encrypt_packet_tls13(gnutls_session_t session,
max = MAX_RECORD_SEND_SIZE(session);
/* make TLS 1.3 form of data */
- fdata_size = plain->size + 1 + min_pad;
+ total = plain->size + 1 + pad_size;
/* check whether padding would exceed max */
- if (fdata_size > max) {
+ if (total > max) {
if (unlikely(max < (ssize_t)plain->size+1))
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
- min_pad = max - plain->size - 1;
- fdata_size = max;
+ pad_size = max - plain->size - 1;
+ total = max;
}
- fdata = gnutls_malloc(fdata_size);
- if (fdata == NULL)
- return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
-
- memcpy(fdata, plain->data, plain->size);
- fdata[plain->size] = type;
- if (min_pad)
- memset(&fdata[plain->size+1], 0, min_pad);
-
/* create authenticated data header */
aad[0] = GNUTLS_APPLICATION_DATA;
aad[1] = 0x03;
aad[2] = 0x03;
- _gnutls_write_uint16(fdata_size+tag_size, &aad[3]);
+ _gnutls_write_uint16(total+tag_size, &aad[3]);
- ret = gnutls_aead_cipher_encrypt(&params->write.ctx.aead,
- nonce, iv_size,
- aad, sizeof(aad),
- tag_size,
- fdata, fdata_size,
- cipher_data, &cipher_size);
- gnutls_free(fdata);
+ auth_iov[0].iov_base = aad;
+ auth_iov[0].iov_len = sizeof(aad);
+
+ iov[0].iov_base = plain->data;
+ iov[0].iov_len = plain->size;
+
+ if (pad_size) {
+ uint8_t *pad = gnutls_calloc(1, 1+pad_size);
+ if (pad == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ pad[0] = type;
+
+ iov[1].iov_base = pad;
+ iov[1].iov_len = 1+pad_size;
+
+ ret = gnutls_aead_cipher_encryptv(&params->write.ctx.aead,
+ nonce, iv_size,
+ auth_iov, 1,
+ tag_size,
+ iov, 2,
+ cipher_data, &cipher_size);
+ gnutls_free(pad);
+ } else {
+ iov[1].iov_base = &type;
+ iov[1].iov_len = 1;
+
+ ret = gnutls_aead_cipher_encryptv(&params->write.ctx.aead,
+ nonce, iv_size,
+ auth_iov, 1,
+ tag_size,
+ iov, 2,
+ cipher_data, &cipher_size);
+ }
if (ret < 0)
return gnutls_assert_val(ret);
diff --git a/lib/crypto-api.c b/lib/crypto-api.c
index 841eb8c541..c3d367b542 100644
--- a/lib/crypto-api.c
+++ b/lib/crypto-api.c
@@ -777,6 +777,255 @@ gnutls_aead_cipher_encrypt(gnutls_aead_cipher_hd_t handle,
return 0;
}
+struct iov_store_st {
+ void *data;
+ size_t size;
+ unsigned allocated;
+};
+
+static void iov_store_free(struct iov_store_st *s)
+{
+ if (s->allocated) {
+ gnutls_free(s->data);
+ s->allocated = 0;
+ }
+}
+
+static int copy_iov(struct iov_store_st *dst, const giovec_t *iov, int iovcnt)
+{
+ memset(dst, 0, sizeof(*dst));
+ if (iovcnt == 0) {
+ return 0;
+ } else if (iovcnt == 1) {
+ dst->data = iov[0].iov_base;
+ dst->size = iov[0].iov_len;
+ /* implies: dst->allocated = 0; */
+ return 0;
+ } else {
+ int i;
+ uint8_t *p;
+
+ dst->size = 0;
+ for (i=0;i<iovcnt;i++)
+ dst->size += iov[i].iov_len;
+ dst->data = gnutls_malloc(dst->size);
+ if (dst->data == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ p = dst->data;
+ for (i=0;i<iovcnt;i++) {
+ memcpy(p, iov[i].iov_base, iov[i].iov_len);
+ p += iov[i].iov_len;
+ }
+
+ dst->allocated = 1;
+ return 0;
+ }
+}
+
+#define AUTH_UPDATE_FINAL(ctx) do { \
+ if (index) { \
+ ret = _gnutls_cipher_auth(ctx, cache, index); \
+ if (unlikely(ret < 0)) \
+ return gnutls_assert_val(ret); \
+ } \
+ } while(0)
+
+#define AUTH_UPDATE(ctx, data, length) do { \
+ if (index) { \
+ unsigned left = blocksize - index; \
+ if (length < left) { \
+ memcpy(cache+index, data, \
+ length); \
+ index += length; \
+ goto __update_done; \
+ } else { \
+ memcpy(cache+index, data, left); \
+ ret = _gnutls_cipher_auth(ctx, cache, blocksize); \
+ if (unlikely(ret < 0)) \
+ return gnutls_assert_val(ret); \
+ data += left; \
+ length -= left; \
+ } \
+ } \
+ if (length >= blocksize) { \
+ unsigned to_proc = (length/blocksize)*blocksize; \
+ ret = _gnutls_cipher_auth(ctx, data, to_proc); \
+ if (unlikely(ret < 0)) \
+ return gnutls_assert_val(ret); \
+ data += to_proc; \
+ length -= to_proc; \
+ } \
+ if (length) \
+ memcpy(cache, data, length); \
+ index = length; \
+ __update_done: \
+ ; \
+ } while(0)
+
+#define ENCRYPT_FINAL(ctx, dst, dst_size) do { \
+ if (index) { \
+ if (unlikely(dst_size < index)) \
+ return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER); \
+ ret = _gnutls_cipher_encrypt2(ctx, cache, index, dst, dst_size); \
+ if (unlikely(ret < 0)) \
+ return gnutls_assert_val(ret); \
+ dst += index; \
+ dst_size -= index; \
+ } \
+ } while(0)
+
+#define ENCRYPT(ctx, data, length, dst, dst_size) do { \
+ if (index) { \
+ unsigned left = blocksize - index; \
+ if (length < left) { \
+ memcpy(cache+index, data, \
+ length); \
+ index += length; \
+ goto __encrypt_done; \
+ } else { \
+ if (unlikely(dst_size < blocksize)) \
+ return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER); \
+ memcpy(cache+index, data, left); \
+ ret = _gnutls_cipher_encrypt2(ctx, cache, blocksize, dst, dst_size); \
+ if (unlikely(ret < 0)) \
+ return gnutls_assert_val(ret); \
+ data += left; \
+ length -= left; \
+ dst += blocksize; \
+ dst_size -= blocksize; \
+ } \
+ } \
+ if (length >= blocksize) { \
+ unsigned to_proc = (length/blocksize)*blocksize; \
+ if (unlikely(dst_size < to_proc)) \
+ return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER); \
+ ret = _gnutls_cipher_encrypt2(ctx, data, to_proc, dst, dst_size); \
+ if (unlikely(ret < 0)) \
+ return gnutls_assert_val(ret); \
+ data += to_proc; \
+ length -= to_proc; \
+ dst += to_proc; \
+ dst_size -= to_proc; \
+ } \
+ if (length) \
+ memcpy(cache, data, length); \
+ index = length; \
+ __encrypt_done: \
+ ; \
+ } while(0)
+
+
+/**
+ * gnutls_aead_cipher_encryptv:
+ * @handle: is a #gnutls_aead_cipher_hd_t type.
+ * @nonce: the nonce to set
+ * @nonce_len: The length of the nonce
+ * @auth_iov: the data to be authenticated
+ * @auth_iovcnt: The number of buffers in @auth_iov
+ * @tag_size: The size of the tag to use (use zero for the default)
+ * @iov: the data to be encrypted
+ * @iovcnt: The number of buffers in @iov
+ * @ctext: the encrypted data
+ * @ctext_len: the length of encrypted data (initially must hold the maximum available size, including space for tag)
+ *
+ * This function will encrypt the provided data buffers using the algorithm
+ * specified by the context. The output data will contain the
+ * authentication tag.
+ *
+ * Returns: Zero or a negative error code on error.
+ *
+ * Since: 3.6.3
+ **/
+int
+gnutls_aead_cipher_encryptv(gnutls_aead_cipher_hd_t handle,
+ const void *nonce, size_t nonce_len,
+ const giovec_t *auth_iov, int auth_iovcnt,
+ size_t tag_size,
+ const giovec_t *iov, int iovcnt,
+ void *ctext, size_t *ctext_len)
+{
+ api_aead_cipher_hd_st *h = handle;
+ int ret;
+ uint8_t *dst;
+ ssize_t dst_size, total = 0, len;
+ uint8_t *p;
+ unsigned i;
+ uint8_t cache[MAX_CIPHER_BLOCK_SIZE];
+ unsigned index;
+ unsigned blocksize = handle->ctx_enc.e->blocksize;
+
+ /* Limitation: this function provides an optimization under the internally registered
+ * AEAD ciphers. When an AEAD cipher is used registered with gnutls_crypto_register_aead_cipher(),
+ * then this becomes a convenience function as it missed the lower-level primitives
+ * necessary for piecemeal encryption. */
+
+ if (tag_size == 0)
+ tag_size = _gnutls_cipher_get_tag_size(h->ctx_enc.e);
+ else if (tag_size > (unsigned)_gnutls_cipher_get_tag_size(h->ctx_enc.e))
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ if (handle->ctx_enc.e->only_aead || handle->ctx_enc.encrypt == NULL) {
+ /* ciphertext cannot be produced in a piecemeal approach */
+ struct iov_store_st auth;
+ struct iov_store_st ptext;
+
+ ret = copy_iov(&auth, auth_iov, auth_iovcnt);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = copy_iov(&ptext, iov, iovcnt);
+ if (ret < 0) {
+ iov_store_free(&auth);
+ return gnutls_assert_val(ret);
+ }
+
+ ret = gnutls_aead_cipher_encrypt(handle, nonce, nonce_len,
+ auth.data, auth.size,
+ tag_size,
+ ptext.data, ptext.size,
+ ctext, ctext_len);
+ iov_store_free(&auth);
+ iov_store_free(&ptext);
+
+ return ret;
+ }
+
+ ret = _gnutls_cipher_setiv(&handle->ctx_enc, nonce, nonce_len);
+ if (unlikely(ret < 0))
+ return gnutls_assert_val(ret);
+
+ index = 0;
+ for (i = 0; i < (unsigned)auth_iovcnt; i++) {
+ p = auth_iov[i].iov_base;
+ len = auth_iov[i].iov_len;
+ AUTH_UPDATE(&handle->ctx_enc, p, len);
+ }
+ AUTH_UPDATE_FINAL(&handle->ctx_enc);
+
+ dst = ctext;
+ dst_size = *ctext_len;
+
+ index = 0;
+ for (i = 0; i < (unsigned)iovcnt; i++) {
+ p = iov[i].iov_base;
+ len = iov[i].iov_len;
+ ENCRYPT(&handle->ctx_enc, p, len, dst, dst_size);
+ total += iov[i].iov_len;
+ }
+ ENCRYPT_FINAL(&handle->ctx_enc, dst, dst_size);
+
+ if ((size_t)dst_size < tag_size)
+ return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
+
+ _gnutls_cipher_tag(&handle->ctx_enc, dst, tag_size);
+
+ total += tag_size;
+ *ctext_len = total;
+
+ return 0;
+}
+
/**
* gnutls_aead_cipher_deinit:
* @handle: is a #gnutls_aead_cipher_hd_t type.
diff --git a/lib/crypto-selftests.c b/lib/crypto-selftests.c
index a637223b0a..1e51dfd6c3 100644
--- a/lib/crypto-selftests.c
+++ b/lib/crypto-selftests.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Red Hat
+ * Copyright (C) 2013-2018 Red Hat
*
* Author: Nikos Mavrogiannopoulos
*
@@ -660,6 +660,191 @@ static int test_cipher_aead_compat(gnutls_cipher_algorithm_t cipher,
}
+#define IOV_PARTS 8
+/* AEAD modes - scatter read */
+static int test_cipher_aead_scatter(gnutls_cipher_algorithm_t cipher,
+ const struct cipher_aead_vectors_st *vectors,
+ size_t vectors_size, unsigned flags)
+{
+ gnutls_aead_cipher_hd_t hd;
+ int ret;
+ unsigned int i, z;
+ uint8_t tmp[384];
+ gnutls_datum_t key, iv;
+ size_t s;
+ unsigned tag_size;
+ giovec_t auth_iov[IOV_PARTS];
+ int auth_iov_len;
+ int iov_len;
+ giovec_t iov[IOV_PARTS];
+
+ _gnutls_debug_log("running scatter (iovec) tests for: %s\n",
+ gnutls_cipher_get_name(cipher));
+
+ for (i = 0; i < vectors_size; i++) {
+ memset(tmp, 0, sizeof(tmp));
+ key.data = (void *) vectors[i].key;
+ key.size = vectors[i].key_size;
+
+ iv.data = (void *) vectors[i].iv;
+ iv.size = vectors[i].iv_size;
+ tag_size = vectors[i].tag_size;
+
+ if (tag_size > gnutls_cipher_get_tag_size(cipher)) {
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+ }
+
+ ret = gnutls_aead_cipher_init(&hd, cipher, &key);
+ if (ret < 0) {
+ _gnutls_debug_log("error initializing: %s\n",
+ gnutls_cipher_get_name(cipher));
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+ }
+
+ s = sizeof(tmp);
+
+ /* single vector */
+ auth_iov_len = 1;
+ auth_iov[0].iov_base = (void*)vectors[i].auth;
+ auth_iov[0].iov_len = vectors[i].auth_size;
+
+ iov_len = 1;
+ iov[0].iov_base = (void*)vectors[i].plaintext;
+ iov[0].iov_len = vectors[i].plaintext_size;
+
+ ret =
+ gnutls_aead_cipher_encryptv(hd,
+ iv.data, iv.size,
+ auth_iov, auth_iov_len,
+ vectors[i].tag_size,
+ iov, iov_len,
+ tmp, &s);
+ if (ret < 0)
+ return
+ gnutls_assert_val
+ (GNUTLS_E_SELF_TEST_ERROR);
+
+ if (s != vectors[i].plaintext_size + tag_size) {
+ return
+ gnutls_assert_val
+ (GNUTLS_E_SELF_TEST_ERROR);
+ }
+
+ if (memcmp(tmp+vectors[i].plaintext_size, vectors[i].tag, tag_size) != 0) {
+ _gnutls_debug_log
+ ("%s test vector %d failed (tag)!\n",
+ gnutls_cipher_get_name(cipher), i);
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+ }
+
+ if (vectors[i].plaintext_size > 0) {
+ if (memcmp
+ (tmp, vectors[i].ciphertext,
+ vectors[i].plaintext_size) != 0) {
+ _gnutls_debug_log
+ ("%s test vector %d failed!\n",
+ gnutls_cipher_get_name(cipher), i);
+
+ return
+ gnutls_assert_val
+ (GNUTLS_E_SELF_TEST_ERROR);
+ }
+ }
+
+ /* multi-vector */
+ auth_iov_len = 0;
+ if (vectors[i].auth_size > IOV_PARTS) {
+ unsigned split = vectors[i].auth_size / IOV_PARTS;
+ assert(split>0);
+ for (z=0;z<IOV_PARTS;z++) {
+ auth_iov[z].iov_base = (void*)(vectors[i].auth+(z*split));
+ if (z==IOV_PARTS-1)
+ auth_iov[z].iov_len = vectors[i].auth_size - z*split;
+ else
+ auth_iov[z].iov_len = split;
+ auth_iov_len++;
+ }
+ } else {
+ auth_iov_len = 1;
+ auth_iov[0].iov_base = (void*)vectors[i].auth;
+ auth_iov[0].iov_len = vectors[i].auth_size;
+ }
+
+ iov_len = 0;
+ if (vectors[i].plaintext_size > IOV_PARTS) {
+ unsigned split = vectors[i].plaintext_size / IOV_PARTS;
+ assert(split>0);
+
+ for (z=0;z<IOV_PARTS;z++) {
+ iov[z].iov_base = (void*)(vectors[i].plaintext+(z*split));
+ if (z==IOV_PARTS-1)
+ iov[z].iov_len = vectors[i].plaintext_size - z*split;
+ else
+ iov[z].iov_len = split;
+ iov_len++;
+ }
+ } else {
+ iov_len = 1;
+ iov[0].iov_base = (void*)vectors[i].plaintext;
+ iov[0].iov_len = vectors[i].plaintext_size;
+ }
+
+ s = sizeof(tmp);
+
+ ret =
+ gnutls_aead_cipher_encryptv(hd,
+ iv.data, iv.size,
+ auth_iov, auth_iov_len,
+ vectors[i].tag_size,
+ iov, iov_len,
+ tmp, &s);
+ if (ret < 0)
+ return
+ gnutls_assert_val
+ (GNUTLS_E_SELF_TEST_ERROR);
+
+ if (s != vectors[i].plaintext_size + tag_size) {
+ return
+ gnutls_assert_val
+ (GNUTLS_E_SELF_TEST_ERROR);
+ }
+
+ if (memcmp(tmp+vectors[i].plaintext_size, vectors[i].tag, tag_size) != 0) {
+ _gnutls_debug_log
+ ("%s test vector %d failed (tag)!\n",
+ gnutls_cipher_get_name(cipher), i);
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+ }
+
+ if (vectors[i].plaintext_size > 0) {
+ if (memcmp
+ (tmp, vectors[i].ciphertext,
+ vectors[i].plaintext_size) != 0) {
+ _gnutls_debug_log
+ ("%s test vector %d failed!\n",
+ gnutls_cipher_get_name(cipher), i);
+
+ return
+ gnutls_assert_val
+ (GNUTLS_E_SELF_TEST_ERROR);
+ }
+ }
+
+
+
+ gnutls_aead_cipher_deinit(hd);
+ }
+
+ _gnutls_debug_log
+ ("%s scatter self check succeeded\n",
+ gnutls_cipher_get_name(cipher));
+
+ if (flags & GNUTLS_SELF_TEST_FLAG_NO_COMPAT)
+ return 0;
+ else
+ return test_cipher_aead_compat(cipher, vectors, vectors_size);
+}
+
/* AEAD modes */
static int test_cipher_aead(gnutls_cipher_algorithm_t cipher,
const struct cipher_aead_vectors_st *vectors,
@@ -792,14 +977,11 @@ static int test_cipher_aead(gnutls_cipher_algorithm_t cipher,
("%s self check succeeded\n",
gnutls_cipher_get_name(cipher));
- /* test the compatibility APIs */
- if (flags & GNUTLS_SELF_TEST_FLAG_NO_COMPAT)
- return 0;
- else
- return test_cipher_aead_compat(cipher, vectors, vectors_size);
+ return test_cipher_aead_scatter(cipher, vectors, vectors_size, flags);
}
+
struct hash_vectors_st {
const uint8_t *plaintext;
unsigned int plaintext_size;
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index 0db05af163..bc0025db30 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -122,7 +122,7 @@ typedef struct {
#define MAX_MAC_KEY_SIZE 64
-#define MAX_CIPHER_BLOCK_SIZE 16
+#define MAX_CIPHER_BLOCK_SIZE 64 /* CHACHA20 */
#define MAX_CIPHER_KEY_SIZE 32
#define MAX_CIPHER_IV_SIZE 16
diff --git a/lib/includes/gnutls/crypto.h b/lib/includes/gnutls/crypto.h
index 43dd37163b..947e25caf9 100644
--- a/lib/includes/gnutls/crypto.h
+++ b/lib/includes/gnutls/crypto.h
@@ -84,6 +84,14 @@ gnutls_aead_cipher_encrypt(gnutls_aead_cipher_hd_t handle,
const void *ptext, size_t ptext_len,
void *ctext, size_t *ctext_len);
+int
+gnutls_aead_cipher_encryptv(gnutls_aead_cipher_hd_t handle,
+ const void *nonce, size_t nonce_len,
+ const giovec_t *auth_iov, int auth_iovcnt,
+ size_t tag_size,
+ const giovec_t *iov, int iovcnt,
+ void *ctext, size_t *ctext_len);
+
void gnutls_aead_cipher_deinit(gnutls_aead_cipher_hd_t handle);
/* Hash - MAC API */
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index cfbd58c40e..2067bca5c9 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1220,6 +1220,7 @@ GNUTLS_3_6_3
gnutls_pkcs11_token_get_ptr;
gnutls_pkcs11_obj_get_ptr;
gnutls_session_ticket_send;
+ gnutls_aead_cipher_encryptv;
} GNUTLS_3_6_2;
GNUTLS_FIPS140_3_4 {
diff --git a/src/benchmark-tls.c b/src/benchmark-tls.c
index 085f6a402a..5c43f827d4 100644
--- a/src/benchmark-tls.c
+++ b/src/benchmark-tls.c
@@ -43,20 +43,22 @@
const char *side = "";
-#define PRIO_DHE_RSA "NONE:+VERS-TLS1.2:+AES-128-GCM:+AEAD:+SIGN-ALL:+COMP-NULL:+DHE-RSA:+GROUP-FFDHE3072"
-#define PRIO_ECDH "NONE:+VERS-TLS1.2:+AES-128-GCM:+AEAD:+SIGN-ALL:+COMP-NULL:+ECDHE-RSA:+CURVE-SECP256R1"
-#define PRIO_ECDH_X25519 "NONE:+VERS-TLS1.2:+AES-128-GCM:+AEAD:+SIGN-ALL:+COMP-NULL:+ECDHE-RSA:+CURVE-X25519"
-#define PRIO_ECDHE_ECDSA "NONE:+VERS-TLS1.2:+AES-128-GCM:+AEAD:+SIGN-ALL:+COMP-NULL:+ECDHE-ECDSA:+CURVE-SECP256R1"
-#define PRIO_ECDH_X25519_ECDSA "NONE:+VERS-TLS1.2:+AES-128-GCM:+AEAD:+SIGN-ALL:+COMP-NULL:+ECDHE-ECDSA:+CURVE-X25519"
-#define PRIO_ECDH_X25519_EDDSA "NONE:+VERS-TLS1.2:+AES-128-GCM:+AEAD:+SIGN-EDDSA-ED25519:+COMP-NULL:+ECDHE-ECDSA:+CURVE-X25519"
+#define PRIO_DHE_RSA "NONE:+VERS-TLS1.3:+AES-128-GCM:+AEAD:+SIGN-ALL:+COMP-NULL:+DHE-RSA:+GROUP-FFDHE3072"
+#define PRIO_ECDH "NONE:+VERS-TLS1.3:+AES-128-GCM:+AEAD:+SIGN-ALL:+COMP-NULL:+ECDHE-RSA:+CURVE-SECP256R1"
+#define PRIO_ECDH_X25519 "NONE:+VERS-TLS1.3:+AES-128-GCM:+AEAD:+SIGN-ALL:+COMP-NULL:+ECDHE-RSA:+CURVE-X25519"
+#define PRIO_ECDHE_ECDSA "NONE:+VERS-TLS1.3:+AES-128-GCM:+AEAD:+SIGN-ALL:+COMP-NULL:+ECDHE-ECDSA:+CURVE-SECP256R1"
+#define PRIO_ECDH_X25519_ECDSA "NONE:+VERS-TLS1.3:+AES-128-GCM:+AEAD:+SIGN-ALL:+COMP-NULL:+ECDHE-ECDSA:+CURVE-X25519"
+#define PRIO_ECDH_X25519_EDDSA "NONE:+VERS-TLS1.3:+AES-128-GCM:+AEAD:+SIGN-EDDSA-ED25519:+COMP-NULL:+ECDHE-ECDSA:+CURVE-X25519"
#define PRIO_RSA "NONE:+VERS-TLS1.2:+AES-128-GCM:+AEAD:+SIGN-ALL:+COMP-NULL:+RSA"
-#define PRIO_ECDH_RSA_PSS "NONE:+VERS-TLS1.2:+AES-128-GCM:+AEAD:+SIGN-RSA-PSS-SHA256:+COMP-NULL:+ECDHE-RSA:+CURVE-SECP256R1"
+#define PRIO_ECDH_RSA_PSS "NONE:+VERS-TLS1.3:+AES-128-GCM:+AEAD:+SIGN-RSA-PSS-SHA256:+COMP-NULL:+ECDHE-RSA:+CURVE-SECP256R1"
#define PRIO_AES_CBC_SHA1 "NONE:+VERS-TLS1.0:+AES-128-CBC:+SHA1:+SIGN-ALL:+COMP-NULL:+RSA"
-#define PRIO_AES_GCM "NONE:+VERS-TLS1.2:+AES-128-GCM:+AEAD:+SIGN-ALL:+COMP-NULL:+RSA"
-#define PRIO_AES_CCM "NONE:+VERS-TLS1.2:+AES-128-CCM:+AEAD:+SIGN-ALL:+COMP-NULL:+RSA"
-#define PRIO_CHACHA_POLY1305 "NONE:+VERS-TLS1.2:+CHACHA20-POLY1305:+AEAD:+SIGN-ALL:+COMP-NULL:+ECDHE-RSA:+CURVE-ALL"
+#define PRIO_TLS12_AES_GCM "NONE:+VERS-TLS1.2:+AES-128-GCM:+AEAD:+SIGN-ALL:+COMP-NULL:+RSA"
+#define PRIO_AES_GCM "NONE:+VERS-TLS1.3:+AES-128-GCM:+AEAD:+SIGN-ALL:+COMP-NULL:+GROUP-ALL"
+#define PRIO_AES_CCM "NONE:+VERS-TLS1.3:+AES-128-CCM:+AEAD:+SIGN-ALL:+COMP-NULL:+GROUP-ALL"
+#define PRIO_TLS12_CHACHA_POLY1305 "NONE:+VERS-TLS1.2:+CHACHA20-POLY1305:+AEAD:+SIGN-ALL:+COMP-NULL:+ECDHE-RSA:+CURVE-ALL"
+#define PRIO_CHACHA_POLY1305 "NONE:+VERS-TLS1.3:+CHACHA20-POLY1305:+AEAD:+SIGN-ALL:+COMP-NULL:+ECDHE-RSA:+CURVE-ALL"
#define PRIO_CAMELLIA_CBC_SHA1 "NONE:+VERS-TLS1.0:+CAMELLIA-128-CBC:+SHA1:+SIGN-ALL:+COMP-NULL:+RSA"
static const int rsa_bits = 3072, ec_bits = 256;
@@ -249,6 +251,7 @@ static void test_ciphersuite(const char *cipher_prio, int size)
int ret;
struct benchmark_st st;
gnutls_packet_t packet;
+ const char *name;
/* Init server */
gnutls_anon_allocate_server_credentials(&s_anoncred);
@@ -292,10 +295,9 @@ static void test_ciphersuite(const char *cipher_prio, int size)
HANDSHAKE(client, server);
- fprintf(stdout, "%38s ",
- gnutls_cipher_suite_get_name(gnutls_kx_get(server),
- gnutls_cipher_get(server),
- gnutls_mac_get(server)));
+ name = gnutls_cipher_get_name(gnutls_cipher_get(server));
+ fprintf(stdout, "%30s - %s ", name, gnutls_protocol_get_name(
+ gnutls_protocol_get_version(server)));
fflush(stdout);
gnutls_rnd(GNUTLS_RND_NONCE, buffer, sizeof(buffer));
@@ -531,8 +533,10 @@ void benchmark_tls(int debug_level, int ciphers)
("Testing throughput in cipher/MAC combinations (payload: %d bytes)\n",
size);
+ test_ciphersuite(PRIO_TLS12_AES_GCM, size);
test_ciphersuite(PRIO_AES_GCM, size);
test_ciphersuite(PRIO_AES_CCM, size);
+ test_ciphersuite(PRIO_TLS12_CHACHA_POLY1305, size);
test_ciphersuite(PRIO_CHACHA_POLY1305, size);
test_ciphersuite(PRIO_AES_CBC_SHA1, size);
test_ciphersuite(PRIO_CAMELLIA_CBC_SHA1, size);
@@ -541,8 +545,10 @@ void benchmark_tls(int debug_level, int ciphers)
printf
("\nTesting throughput in cipher/MAC combinations (payload: %d bytes)\n",
size);
+ test_ciphersuite(PRIO_TLS12_AES_GCM, size);
test_ciphersuite(PRIO_AES_GCM, size);
test_ciphersuite(PRIO_AES_CCM, size);
+ test_ciphersuite(PRIO_TLS12_CHACHA_POLY1305, size);
test_ciphersuite(PRIO_CHACHA_POLY1305, size);
test_ciphersuite(PRIO_AES_CBC_SHA1, size);
test_ciphersuite(PRIO_CAMELLIA_CBC_SHA1, size);
diff --git a/symbols.last b/symbols.last
index 3d3824262b..c5b94fdd1e 100644
--- a/symbols.last
+++ b/symbols.last
@@ -6,6 +6,7 @@ _gnutls_global_init_skip@GNUTLS_3_4
gnutls_aead_cipher_decrypt@GNUTLS_3_4
gnutls_aead_cipher_deinit@GNUTLS_3_4
gnutls_aead_cipher_encrypt@GNUTLS_3_4
+gnutls_aead_cipher_encryptv@GNUTLS_3_6_3
gnutls_aead_cipher_init@GNUTLS_3_4
gnutls_alert_get@GNUTLS_3_4
gnutls_alert_get_name@GNUTLS_3_4