diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | NEWS | 7 | ||||
-rw-r--r-- | devel/libgnutls-latest-x86_64.abi | 26 | ||||
-rw-r--r-- | devel/symbols.last | 3 | ||||
-rw-r--r-- | doc/Makefile.am | 4 | ||||
-rw-r--r-- | doc/manpages/Makefile.am | 2 | ||||
-rw-r--r-- | lib/crypto-api.c | 356 | ||||
-rw-r--r-- | lib/includes/gnutls/crypto.h | 14 | ||||
-rw-r--r-- | lib/libgnutls.map | 7 | ||||
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rw-r--r-- | tests/aead-cipher-vec.c | 123 |
11 files changed, 541 insertions, 4 deletions
diff --git a/.gitignore b/.gitignore index 26d29fcf34..606257a025 100644 --- a/.gitignore +++ b/.gitignore @@ -331,6 +331,7 @@ tags tests/*/out tests/Makefile tests/Makefile.in +tests/aead-cipher-vec tests/alerts tests/alpn-server-prec tests/anonself @@ -12,6 +12,13 @@ See the end for copying conditions. GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE when calling gnutls_privkey_sign_*() functions (#94). +** libgnutls: add gnutls_aead_cipher_encryptv2 and gnutls_aead_cipher_decryptv2 + functions that will perform in-place encryption/decryption on data buffers (#718). + +** API and ABI modifications: +gnutls_aead_cipher_encryptv2: Added +gnutls_aead_cipher_decryptv2: Added + * Version 3.6.9 (released 2019-07-25) ** libgnutls: add gnutls_hash_copy/gnutls_hmac_copy functions that will create a copy diff --git a/devel/libgnutls-latest-x86_64.abi b/devel/libgnutls-latest-x86_64.abi index 17e8d40663..49044fe938 100644 --- a/devel/libgnutls-latest-x86_64.abi +++ b/devel/libgnutls-latest-x86_64.abi @@ -59,9 +59,11 @@ <elf-symbol name='_rsa_generate_fips186_4_keypair' version='GNUTLS_FIPS140_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='dsa_generate_dss_keypair' version='GNUTLS_FIPS140_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='gnutls_aead_cipher_decrypt' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='gnutls_aead_cipher_decryptv2' version='GNUTLS_3_6_10' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='gnutls_aead_cipher_deinit' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='gnutls_aead_cipher_encrypt' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='gnutls_aead_cipher_encryptv' version='GNUTLS_3_6_3' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='gnutls_aead_cipher_encryptv2' version='GNUTLS_3_6_10' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='gnutls_aead_cipher_init' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='gnutls_alert_get' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='gnutls_alert_get_name' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> @@ -8917,6 +8919,30 @@ <parameter type-id='type-id-740' name='handle'/> <return type-id='type-id-112'/> </function-decl> + <function-decl name='gnutls_aead_cipher_decryptv2' mangled-name='gnutls_aead_cipher_decryptv2' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='gnutls_aead_cipher_decryptv2@@GNUTLS_3_6_10'> + <parameter type-id='type-id-740' name='handle'/> + <parameter type-id='type-id-102' name='nonce'/> + <parameter type-id='type-id-100' name='nonce_len'/> + <parameter type-id='type-id-250' name='auth_iov'/> + <parameter type-id='type-id-22' name='auth_iovcnt'/> + <parameter type-id='type-id-250' name='iov'/> + <parameter type-id='type-id-22' name='iovcnt'/> + <parameter type-id='type-id-102' name='tag'/> + <parameter type-id='type-id-100' name='tag_size'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='gnutls_aead_cipher_encryptv2' mangled-name='gnutls_aead_cipher_encryptv2' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='gnutls_aead_cipher_encryptv2@@GNUTLS_3_6_10'> + <parameter type-id='type-id-740' name='handle'/> + <parameter type-id='type-id-102' name='nonce'/> + <parameter type-id='type-id-100' name='nonce_len'/> + <parameter type-id='type-id-250' name='auth_iov'/> + <parameter type-id='type-id-22' name='auth_iovcnt'/> + <parameter type-id='type-id-250' name='iov'/> + <parameter type-id='type-id-22' name='iovcnt'/> + <parameter type-id='type-id-102' name='tag'/> + <parameter type-id='type-id-423' name='tag_size'/> + <return type-id='type-id-22'/> + </function-decl> <function-decl name='gnutls_aead_cipher_encryptv' mangled-name='gnutls_aead_cipher_encryptv' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='gnutls_aead_cipher_encryptv@@GNUTLS_3_6_3'> <parameter type-id='type-id-740' name='handle'/> <parameter type-id='type-id-102' name='nonce'/> diff --git a/devel/symbols.last b/devel/symbols.last index e5ff89d5e4..730d75043e 100644 --- a/devel/symbols.last +++ b/devel/symbols.last @@ -1,5 +1,6 @@ GNUTLS_3_4@GNUTLS_3_4 GNUTLS_3_6_0@GNUTLS_3_6_0 +GNUTLS_3_6_10@GNUTLS_3_6_10 GNUTLS_3_6_2@GNUTLS_3_6_2 GNUTLS_3_6_3@GNUTLS_3_6_3 GNUTLS_3_6_4@GNUTLS_3_6_4 @@ -9,8 +10,10 @@ GNUTLS_3_6_8@GNUTLS_3_6_8 GNUTLS_3_6_9@GNUTLS_3_6_9 _gnutls_global_init_skip@GNUTLS_3_4 gnutls_aead_cipher_decrypt@GNUTLS_3_4 +gnutls_aead_cipher_decryptv2@GNUTLS_3_6_10 gnutls_aead_cipher_deinit@GNUTLS_3_4 gnutls_aead_cipher_encrypt@GNUTLS_3_4 +gnutls_aead_cipher_encryptv2@GNUTLS_3_6_10 gnutls_aead_cipher_encryptv@GNUTLS_3_6_3 gnutls_aead_cipher_init@GNUTLS_3_4 gnutls_alert_get@GNUTLS_3_4 diff --git a/doc/Makefile.am b/doc/Makefile.am index 6d21d74820..add63c23d5 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -635,12 +635,16 @@ FUNCS += functions/dane_verify_session_crt FUNCS += functions/dane_verify_session_crt.short FUNCS += functions/gnutls_aead_cipher_decrypt FUNCS += functions/gnutls_aead_cipher_decrypt.short +FUNCS += functions/gnutls_aead_cipher_decryptv2 +FUNCS += functions/gnutls_aead_cipher_decryptv2.short 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_encryptv2 +FUNCS += functions/gnutls_aead_cipher_encryptv2.short FUNCS += functions/gnutls_aead_cipher_init FUNCS += functions/gnutls_aead_cipher_init.short FUNCS += functions/gnutls_alert_get diff --git a/doc/manpages/Makefile.am b/doc/manpages/Makefile.am index d06c180138..ee855adf35 100644 --- a/doc/manpages/Makefile.am +++ b/doc/manpages/Makefile.am @@ -119,9 +119,11 @@ APIMANS += dane_verify_crt.3 APIMANS += dane_verify_crt_raw.3 APIMANS += dane_verify_session_crt.3 APIMANS += gnutls_aead_cipher_decrypt.3 +APIMANS += gnutls_aead_cipher_decryptv2.3 APIMANS += gnutls_aead_cipher_deinit.3 APIMANS += gnutls_aead_cipher_encrypt.3 APIMANS += gnutls_aead_cipher_encryptv.3 +APIMANS += gnutls_aead_cipher_encryptv2.3 APIMANS += gnutls_aead_cipher_init.3 APIMANS += gnutls_alert_get.3 APIMANS += gnutls_alert_get_name.3 diff --git a/lib/crypto-api.c b/lib/crypto-api.c index 70107fed0a..2834c01996 100644 --- a/lib/crypto-api.c +++ b/lib/crypto-api.c @@ -885,7 +885,26 @@ static void iov_store_free(struct iov_store_st *s) } } -static int copy_iov(struct iov_store_st *dst, const giovec_t *iov, int iovcnt) +static int iov_store_grow(struct iov_store_st *s, size_t length) +{ + if (s->allocated || s->data == NULL) { + s->size += length; + s->data = gnutls_realloc(s->data, s->size); + if (s->data == NULL) + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + s->allocated = 1; + } else { + void *data = s->data; + size_t size = s->size + length; + s->data = gnutls_malloc(size); + memcpy(s->data, data, s->size); + s->size += length; + } + return 0; +} + +static int +copy_from_iov(struct iov_store_st *dst, const giovec_t *iov, int iovcnt) { memset(dst, 0, sizeof(*dst)); if (iovcnt == 0) { @@ -917,6 +936,27 @@ static int copy_iov(struct iov_store_st *dst, const giovec_t *iov, int iovcnt) } } +static int +copy_to_iov(struct iov_store_st *src, size_t size, + const giovec_t *iov, int iovcnt) +{ + size_t offset = 0; + int i; + + if (unlikely(src->size < size)) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + for (i = 0; i < iovcnt && size > 0; i++) { + size_t to_copy = MIN(size, iov[i].iov_len); + memcpy(iov[i].iov_base, (uint8_t *) src->data + offset, to_copy); + offset += to_copy; + size -= to_copy; + } + if (size > 0) + return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER); + return 0; +} + /** * gnutls_aead_cipher_encryptv: @@ -971,11 +1011,11 @@ gnutls_aead_cipher_encryptv(gnutls_aead_cipher_hd_t handle, struct iov_store_st auth; struct iov_store_st ptext; - ret = copy_iov(&auth, auth_iov, auth_iovcnt); + ret = copy_from_iov(&auth, auth_iov, auth_iovcnt); if (ret < 0) return gnutls_assert_val(ret); - ret = copy_iov(&ptext, iov, iovcnt); + ret = copy_from_iov(&ptext, iov, iovcnt); if (ret < 0) { iov_store_free(&auth); return gnutls_assert_val(ret); @@ -1067,6 +1107,316 @@ gnutls_aead_cipher_encryptv(gnutls_aead_cipher_hd_t handle, } /** + * gnutls_aead_cipher_encryptv2: + * @handle: is a #gnutls_aead_cipher_hd_t type. + * @nonce: the nonce to set + * @nonce_len: The length of the nonce + * @auth_iov: additional data to be authenticated + * @auth_iovcnt: The number of buffers in @auth_iov + * @iov: the data to be encrypted + * @iovcnt: The number of buffers in @iov + * @tag: The authentication tag + * @tag_size: The size of the tag to use (use zero for the default) + * + * This is similar to gnutls_aead_cipher_encrypt(), but it performs + * in-place encryption on the provided data buffers. + * + * Returns: Zero or a negative error code on error. + * + * Since: 3.6.10 + **/ +int +gnutls_aead_cipher_encryptv2(gnutls_aead_cipher_hd_t handle, + const void *nonce, size_t nonce_len, + const giovec_t *auth_iov, int auth_iovcnt, + const giovec_t *iov, int iovcnt, + void *tag, size_t *tag_size) +{ + api_aead_cipher_hd_st *h = handle; + ssize_t ret; + uint8_t *p; + ssize_t blocksize = handle->ctx_enc.e->blocksize; + struct iov_iter_st iter; + size_t blocks; + size_t _tag_size; + + if (tag_size == NULL || *tag_size == 0) + _tag_size = _gnutls_cipher_get_tag_size(h->ctx_enc.e); + else + _tag_size = *tag_size; + + if (_tag_size > (unsigned)_gnutls_cipher_get_tag_size(h->ctx_enc.e)) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + /* 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 (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; + size_t ptext_size; + + ret = copy_from_iov(&auth, auth_iov, auth_iovcnt); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = copy_from_iov(&ptext, iov, iovcnt); + if (ret < 0) { + gnutls_assert(); + goto fallback_fail; + } + + ptext_size = ptext.size; + + /* append space for tag */ + ret = iov_store_grow(&ptext, _tag_size); + if (ret < 0) { + gnutls_assert(); + goto fallback_fail; + } + + ret = gnutls_aead_cipher_encrypt(handle, nonce, nonce_len, + auth.data, auth.size, + _tag_size, + ptext.data, ptext_size, + ptext.data, &ptext.size); + if (ret < 0) { + gnutls_assert(); + goto fallback_fail; + } + + ret = copy_to_iov(&ptext, ptext_size, iov, iovcnt); + if (ret < 0) { + gnutls_assert(); + goto fallback_fail; + } + + if (tag != NULL) + memcpy(tag, + (uint8_t *) ptext.data + ptext_size, + _tag_size); + if (tag_size != NULL) + *tag_size = _tag_size; + + fallback_fail: + 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); + + ret = _gnutls_iov_iter_init(&iter, auth_iov, auth_iovcnt, blocksize); + if (unlikely(ret < 0)) + return gnutls_assert_val(ret); + while (1) { + ret = _gnutls_iov_iter_next(&iter, &p); + if (unlikely(ret < 0)) + return gnutls_assert_val(ret); + if (ret == 0) + break; + blocks = ret; + ret = _gnutls_cipher_auth(&handle->ctx_enc, p, + blocksize * blocks); + if (unlikely(ret < 0)) + return gnutls_assert_val(ret); + } + if (iter.block_offset > 0) { + ret = _gnutls_cipher_auth(&handle->ctx_enc, + iter.block, iter.block_offset); + if (unlikely(ret < 0)) + return gnutls_assert_val(ret); + } + + ret = _gnutls_iov_iter_init(&iter, iov, iovcnt, blocksize); + if (unlikely(ret < 0)) + return gnutls_assert_val(ret); + while (1) { + ret = _gnutls_iov_iter_next(&iter, &p); + if (unlikely(ret < 0)) + return gnutls_assert_val(ret); + if (ret == 0) + break; + blocks = ret; + ret = _gnutls_cipher_encrypt2(&handle->ctx_enc, + p, blocksize * blocks, + p, blocksize * blocks); + if (unlikely(ret < 0)) + return gnutls_assert_val(ret); + } + if (iter.block_offset > 0) { + ret = _gnutls_cipher_encrypt2(&handle->ctx_enc, + iter.block, iter.block_offset, + iter.block, iter.block_offset); + if (unlikely(ret < 0)) + return gnutls_assert_val(ret); + } + + if (tag != NULL) + _gnutls_cipher_tag(&handle->ctx_enc, tag, _tag_size); + if (tag_size != NULL) + *tag_size = _tag_size; + + return 0; +} + +/** + * gnutls_aead_cipher_decryptv2: + * @handle: is a #gnutls_aead_cipher_hd_t type. + * @nonce: the nonce to set + * @nonce_len: The length of the nonce + * @auth_iov: additional data to be authenticated + * @auth_iovcnt: The number of buffers in @auth_iov + * @iov: the data to decrypt + * @iovcnt: The number of buffers in @iov + * @tag: The authentication tag + * @tag_size: The size of the tag to use (use zero for the default) + * + * This is similar to gnutls_aead_cipher_decrypt(), but it performs + * in-place encryption on the provided data buffers. + * + * Returns: Zero or a negative error code on error. + * + * Since: 3.6.10 + **/ +int +gnutls_aead_cipher_decryptv2(gnutls_aead_cipher_hd_t handle, + const void *nonce, size_t nonce_len, + const giovec_t *auth_iov, int auth_iovcnt, + const giovec_t *iov, int iovcnt, + void *tag, size_t tag_size) +{ + api_aead_cipher_hd_st *h = handle; + ssize_t ret; + uint8_t *p; + ssize_t blocksize = handle->ctx_enc.e->blocksize; + struct iov_iter_st iter; + size_t blocks; + uint8_t _tag[MAX_HASH_SIZE]; + + 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); + + /* 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 (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 ctext; + size_t ctext_size; + + ret = copy_from_iov(&auth, auth_iov, auth_iovcnt); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = copy_from_iov(&ctext, iov, iovcnt); + if (ret < 0) { + gnutls_assert(); + goto fallback_fail; + } + + ctext_size = ctext.size; + + /* append tag */ + ret = iov_store_grow(&ctext, tag_size); + if (ret < 0) { + gnutls_assert(); + goto fallback_fail; + } + memcpy((uint8_t *) ctext.data + ctext_size, tag, tag_size); + + ret = gnutls_aead_cipher_decrypt(handle, nonce, nonce_len, + auth.data, auth.size, + tag_size, + ctext.data, ctext.size, + ctext.data, &ctext_size); + if (ret < 0) { + gnutls_assert(); + goto fallback_fail; + } + + ret = copy_to_iov(&ctext, ctext_size, iov, iovcnt); + if (ret < 0) { + gnutls_assert(); + goto fallback_fail; + } + + fallback_fail: + iov_store_free(&auth); + iov_store_free(&ctext); + + return ret; + } + + ret = _gnutls_cipher_setiv(&handle->ctx_enc, nonce, nonce_len); + if (unlikely(ret < 0)) + return gnutls_assert_val(ret); + + ret = _gnutls_iov_iter_init(&iter, auth_iov, auth_iovcnt, blocksize); + if (unlikely(ret < 0)) + return gnutls_assert_val(ret); + while (1) { + ret = _gnutls_iov_iter_next(&iter, &p); + if (unlikely(ret < 0)) + return gnutls_assert_val(ret); + if (ret == 0) + break; + blocks = ret; + ret = _gnutls_cipher_auth(&handle->ctx_enc, p, + blocksize * blocks); + if (unlikely(ret < 0)) + return gnutls_assert_val(ret); + } + if (iter.block_offset > 0) { + ret = _gnutls_cipher_auth(&handle->ctx_enc, + iter.block, iter.block_offset); + if (unlikely(ret < 0)) + return gnutls_assert_val(ret); + } + + ret = _gnutls_iov_iter_init(&iter, iov, iovcnt, blocksize); + if (unlikely(ret < 0)) + return gnutls_assert_val(ret); + while (1) { + ret = _gnutls_iov_iter_next(&iter, &p); + if (unlikely(ret < 0)) + return gnutls_assert_val(ret); + if (ret == 0) + break; + blocks = ret; + ret = _gnutls_cipher_decrypt2(&handle->ctx_enc, + p, blocksize * blocks, + p, blocksize * blocks); + if (unlikely(ret < 0)) + return gnutls_assert_val(ret); + } + if (iter.block_offset > 0) { + ret = _gnutls_cipher_decrypt2(&handle->ctx_enc, + iter.block, iter.block_offset, + iter.block, iter.block_offset); + if (unlikely(ret < 0)) + return gnutls_assert_val(ret); + } + + if (tag != NULL) { + _gnutls_cipher_tag(&handle->ctx_enc, _tag, tag_size); + if (gnutls_memcmp(_tag, tag, tag_size) != 0) + return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); + } + + return 0; +} + +/** * gnutls_aead_cipher_deinit: * @handle: is a #gnutls_aead_cipher_hd_t type. * diff --git a/lib/includes/gnutls/crypto.h b/lib/includes/gnutls/crypto.h index d2b8cae8f4..4d4926c86a 100644 --- a/lib/includes/gnutls/crypto.h +++ b/lib/includes/gnutls/crypto.h @@ -92,6 +92,20 @@ gnutls_aead_cipher_encryptv(gnutls_aead_cipher_hd_t handle, const giovec_t *iov, int iovcnt, void *ctext, size_t *ctext_len); +int +gnutls_aead_cipher_encryptv2(gnutls_aead_cipher_hd_t handle, + const void *nonce, size_t nonce_len, + const giovec_t *auth_iov, int auth_iovcnt, + const giovec_t *iov, int iovcnt, + void *tag, size_t *tag_size); + +int +gnutls_aead_cipher_decryptv2(gnutls_aead_cipher_hd_t handle, + const void *nonce, size_t nonce_len, + const giovec_t *auth_iov, int auth_iovcnt, + const giovec_t *iov, int iovcnt, + void *tag, size_t tag_size); + 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 fc93c0857f..f83a21e9bc 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -1294,6 +1294,13 @@ GNUTLS_3_6_9 gnutls_hash_copy; } GNUTLS_3_6_8; +GNUTLS_3_6_10 +{ + global: + gnutls_aead_cipher_encryptv2; + gnutls_aead_cipher_decryptv2; +} GNUTLS_3_6_9; + GNUTLS_FIPS140_3_4 { global: gnutls_cipher_self_test; diff --git a/tests/Makefile.am b/tests/Makefile.am index a2883570f3..075c2728f3 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -214,7 +214,7 @@ ctests += mini-record-2 simple gnutls_hmac_fast set_pkcs12_cred cert certuniquei null_retrieve_function tls-record-size-limit tls-crt_type-neg \ resume-with-stek-expiration resume-with-previous-stek rawpk-api \ tls-record-size-limit-asym dh-compute ecdh-compute sign-verify-data-newapi \ - sign-verify-newapi sign-verify-deterministic iov + sign-verify-newapi sign-verify-deterministic iov aead-cipher-vec if HAVE_SECCOMP_TESTS ctests += dtls-with-seccomp tls-with-seccomp dtls-client-with-seccomp tls-client-with-seccomp diff --git a/tests/aead-cipher-vec.c b/tests/aead-cipher-vec.c new file mode 100644 index 0000000000..6c2542cf10 --- /dev/null +++ b/tests/aead-cipher-vec.c @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2019 Red Hat, Inc. + * + * Author: Daiki Ueno + * + * This file is part of GnuTLS. + * + * GnuTLS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuTLS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <gnutls/crypto.h> + +#include <assert.h> +#include <stdint.h> +#include <string.h> +#include "utils.h" + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "<%d>| %s", level, str); +} + +/* Test whether gnutls_aead_cipher_{en,de}crypt_vec works */ +static void start(const char *name, int algo) +{ + int ret; + gnutls_aead_cipher_hd_t ch; + uint8_t key16[64]; + uint8_t iv16[32]; + uint8_t auth[128]; + uint8_t data[128+64]; + gnutls_datum_t key, iv; + giovec_t iov[2]; + giovec_t auth_iov[2]; + uint8_t tag[64]; + size_t tag_size = 0; + + key.data = key16; + key.size = gnutls_cipher_get_key_size(algo); + assert(key.size <= sizeof(key16)); + + iv.data = iv16; + iv.size = gnutls_cipher_get_iv_size(algo); + assert(iv.size <= sizeof(iv16)); + + memset(iv.data, 0xff, iv.size); + memset(key.data, 0xfe, key.size); + memset(data, 0xfa, 128); + memset(auth, 0xaa, sizeof(auth)); + + iov[0].iov_base = data; + iov[0].iov_len = 64; + iov[1].iov_base = data + 64; + iov[1].iov_len = 64; + + auth_iov[0].iov_base = auth; + auth_iov[0].iov_len = 64; + auth_iov[1].iov_base = auth + 64; + auth_iov[1].iov_len = 64; + + success("trying %s\n", name); + + ret = + gnutls_aead_cipher_init(&ch, algo, &key); + if (ret < 0) + fail("gnutls_cipher_init: %s\n", gnutls_strerror(ret)); + + ret = gnutls_aead_cipher_encryptv2(ch, + iv.data, iv.size, + auth_iov, 2, + iov, 2, + tag, &tag_size); + if (ret < 0) + fail("could not encrypt data: %s\n", gnutls_strerror(ret)); + + ret = gnutls_aead_cipher_decryptv2(ch, + iv.data, iv.size, + auth_iov, 2, + iov, 2, + tag, tag_size); + if (ret < 0) + fail("could not decrypt data: %s\n", gnutls_strerror(ret)); + + gnutls_aead_cipher_deinit(ch); +} + +void +doit(void) +{ + int ret; + + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + ret = global_init(); + if (ret < 0) { + fail("Cannot initialize library\n"); /*errcode 1 */ + } + + start("aes-128-gcm", GNUTLS_CIPHER_AES_128_GCM); + start("aes-256-gcm", GNUTLS_CIPHER_AES_256_GCM); + start("aes-128-ccm", GNUTLS_CIPHER_AES_128_CCM); + if (!gnutls_fips140_mode_enabled()) + start("chacha20-poly1305", GNUTLS_CIPHER_CHACHA20_POLY1305); + + gnutls_global_deinit(); +} |