/* * Copyright (C) 2008-2012 Free Software Foundation, Inc. * * Author: Nikos Mavrogiannopoulos * * This file is part of GNUTLS. * * The GNUTLS library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library 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 * Lesser 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 * */ /* This file provides the backend hash/mac API for nettle. */ #include "gnutls_int.h" #include #include "errors.h" #include #include #include #include #include #include #include #include #include #if ENABLE_GOST #include "gost/hmac-gost.h" #ifndef HAVE_NETTLE_GOST28147_SET_KEY #include "gost/gost28147.h" #endif #include "gost/cmac.h" #endif #include typedef void (*update_func)(void *, size_t, const uint8_t *); typedef void (*digest_func)(void *, size_t, uint8_t *); typedef void (*set_key_func)(void *, size_t, const uint8_t *); typedef void (*set_nonce_func)(void *, size_t, const uint8_t *); static int wrap_nettle_hash_init(gnutls_digest_algorithm_t algo, void **_ctx); struct md5_sha1_ctx { struct md5_ctx md5; struct sha1_ctx sha1; }; struct gmac_ctx { unsigned int pos; uint8_t buffer[GCM_BLOCK_SIZE]; struct gcm_key key; struct gcm_ctx ctx; nettle_cipher_func *encrypt; union { struct aes128_ctx aes128; struct aes192_ctx aes192; struct aes256_ctx aes256; } cipher; }; struct nettle_hash_ctx { union { struct md5_ctx md5; struct sha224_ctx sha224; struct sha256_ctx sha256; struct sha384_ctx sha384; struct sha512_ctx sha512; struct sha3_224_ctx sha3_224; struct sha3_256_ctx sha3_256; struct sha3_384_ctx sha3_384; struct sha3_512_ctx sha3_512; struct sha1_ctx sha1; struct md2_ctx md2; struct md5_sha1_ctx md5_sha1; #if ENABLE_GOST struct gosthash94cp_ctx gosthash94cp; struct streebog256_ctx streebog256; struct streebog512_ctx streebog512; #endif } ctx; void *ctx_ptr; gnutls_digest_algorithm_t algo; size_t length; update_func update; digest_func digest; }; struct nettle_mac_ctx { union { struct hmac_md5_ctx md5; struct hmac_sha224_ctx sha224; struct hmac_sha256_ctx sha256; struct hmac_sha384_ctx sha384; struct hmac_sha512_ctx sha512; struct hmac_sha1_ctx sha1; #if ENABLE_GOST struct hmac_gosthash94cp_ctx gosthash94cp; struct hmac_streebog256_ctx streebog256; struct hmac_streebog512_ctx streebog512; struct gost28147_imit_ctx gost28147_imit; struct cmac_magma_ctx magma; struct cmac_kuznyechik_ctx kuznyechik; #endif struct umac96_ctx umac96; struct umac128_ctx umac128; struct cmac_aes128_ctx cmac128; struct cmac_aes256_ctx cmac256; struct gmac_ctx gmac; } ctx; void *ctx_ptr; gnutls_mac_algorithm_t algo; size_t length; update_func update; digest_func digest; set_key_func set_key; set_nonce_func set_nonce; }; #if ENABLE_GOST static void _wrap_gost28147_imit_set_key_tc26z(void *ctx, size_t len, const uint8_t *key) { gost28147_imit_set_param(ctx, &gost28147_param_TC26_Z); gost28147_imit_set_key(ctx, len, key); } static void _wrap_cmac_magma_set_key(void *ctx, size_t len, const uint8_t *key) { cmac_magma_set_key(ctx, key); } static void _wrap_cmac_kuznyechik_set_key(void *ctx, size_t len, const uint8_t *key) { cmac_kuznyechik_set_key(ctx, key); } #endif static void _wrap_umac96_set_key(void *ctx, size_t len, const uint8_t *key) { if (unlikely(len != 16)) abort(); umac96_set_key(ctx, key); } static void _wrap_umac128_set_key(void *ctx, size_t len, const uint8_t *key) { if (unlikely(len != 16)) abort(); umac128_set_key(ctx, key); } static void _wrap_cmac128_set_key(void *ctx, size_t len, const uint8_t *key) { if (unlikely(len != 16)) abort(); cmac_aes128_set_key(ctx, key); } static void _wrap_cmac256_set_key(void *ctx, size_t len, const uint8_t *key) { if (unlikely(len != 32)) abort(); cmac_aes256_set_key(ctx, key); } static void _wrap_gmac_aes128_set_key(void *_ctx, size_t len, const uint8_t *key) { struct gmac_ctx *ctx = _ctx; if (unlikely(len != 16)) abort(); aes128_set_encrypt_key(&ctx->cipher.aes128, key); gcm_set_key(&ctx->key, &ctx->cipher, ctx->encrypt); ctx->pos = 0; } static void _wrap_gmac_aes192_set_key(void *_ctx, size_t len, const uint8_t *key) { struct gmac_ctx *ctx = _ctx; if (unlikely(len != 24)) abort(); aes192_set_encrypt_key(&ctx->cipher.aes192, key); gcm_set_key(&ctx->key, &ctx->cipher, ctx->encrypt); ctx->pos = 0; } static void _wrap_gmac_aes256_set_key(void *_ctx, size_t len, const uint8_t *key) { struct gmac_ctx *ctx = _ctx; if (unlikely(len != 32)) abort(); aes256_set_encrypt_key(&ctx->cipher.aes256, key); gcm_set_key(&ctx->key, &ctx->cipher, ctx->encrypt); ctx->pos = 0; } static void _wrap_gmac_set_nonce(void *_ctx, size_t nonce_length, const uint8_t *nonce) { struct gmac_ctx *ctx = _ctx; gcm_set_iv(&ctx->ctx, &ctx->key, nonce_length, nonce); } static void _wrap_gmac_update(void *_ctx, size_t length, const uint8_t *data) { struct gmac_ctx *ctx = _ctx; if (ctx->pos + length < GCM_BLOCK_SIZE) { memcpy(&ctx->buffer[ctx->pos], data, length); ctx->pos += length; return; } if (ctx->pos) { memcpy(&ctx->buffer[ctx->pos], data, GCM_BLOCK_SIZE - ctx->pos); gcm_update(&ctx->ctx, &ctx->key, GCM_BLOCK_SIZE, ctx->buffer); data += GCM_BLOCK_SIZE - ctx->pos; length -= GCM_BLOCK_SIZE - ctx->pos; } if (length >= GCM_BLOCK_SIZE) { gcm_update(&ctx->ctx, &ctx->key, length / GCM_BLOCK_SIZE * GCM_BLOCK_SIZE, data); data += length / GCM_BLOCK_SIZE * GCM_BLOCK_SIZE; length %= GCM_BLOCK_SIZE; } memcpy(ctx->buffer, data, length); ctx->pos = length; } static void _wrap_gmac_digest(void *_ctx, size_t length, uint8_t *digest) { struct gmac_ctx *ctx = _ctx; if (ctx->pos) gcm_update(&ctx->ctx, &ctx->key, ctx->pos, ctx->buffer); gcm_digest(&ctx->ctx, &ctx->key, &ctx->cipher, ctx->encrypt, length, digest); ctx->pos = 0; } static int _mac_ctx_init(gnutls_mac_algorithm_t algo, struct nettle_mac_ctx *ctx) { /* Any FIPS140-2 related enforcement is performed on * gnutls_hash_init() and gnutls_hmac_init() */ ctx->set_nonce = NULL; switch (algo) { case GNUTLS_MAC_MD5: ctx->update = (update_func)hmac_md5_update; ctx->digest = (digest_func)hmac_md5_digest; ctx->set_key = (set_key_func)hmac_md5_set_key; ctx->ctx_ptr = &ctx->ctx.md5; ctx->length = MD5_DIGEST_SIZE; break; case GNUTLS_MAC_SHA1: ctx->update = (update_func)hmac_sha1_update; ctx->digest = (digest_func)hmac_sha1_digest; ctx->set_key = (set_key_func)hmac_sha1_set_key; ctx->ctx_ptr = &ctx->ctx.sha1; ctx->length = SHA1_DIGEST_SIZE; break; case GNUTLS_MAC_SHA224: ctx->update = (update_func)hmac_sha224_update; ctx->digest = (digest_func)hmac_sha224_digest; ctx->set_key = (set_key_func)hmac_sha224_set_key; ctx->ctx_ptr = &ctx->ctx.sha224; ctx->length = SHA224_DIGEST_SIZE; break; case GNUTLS_MAC_SHA256: ctx->update = (update_func)hmac_sha256_update; ctx->digest = (digest_func)hmac_sha256_digest; ctx->set_key = (set_key_func)hmac_sha256_set_key; ctx->ctx_ptr = &ctx->ctx.sha256; ctx->length = SHA256_DIGEST_SIZE; break; case GNUTLS_MAC_SHA384: ctx->update = (update_func)hmac_sha384_update; ctx->digest = (digest_func)hmac_sha384_digest; ctx->set_key = (set_key_func)hmac_sha384_set_key; ctx->ctx_ptr = &ctx->ctx.sha384; ctx->length = SHA384_DIGEST_SIZE; break; case GNUTLS_MAC_SHA512: ctx->update = (update_func)hmac_sha512_update; ctx->digest = (digest_func)hmac_sha512_digest; ctx->set_key = (set_key_func)hmac_sha512_set_key; ctx->ctx_ptr = &ctx->ctx.sha512; ctx->length = SHA512_DIGEST_SIZE; break; #if ENABLE_GOST case GNUTLS_MAC_GOSTR_94: ctx->update = (update_func)hmac_gosthash94cp_update; ctx->digest = (digest_func)hmac_gosthash94cp_digest; ctx->set_key = (set_key_func)hmac_gosthash94cp_set_key; ctx->ctx_ptr = &ctx->ctx.gosthash94cp; ctx->length = GOSTHASH94CP_DIGEST_SIZE; break; case GNUTLS_MAC_STREEBOG_256: ctx->update = (update_func)hmac_streebog256_update; ctx->digest = (digest_func)hmac_streebog256_digest; ctx->set_key = (set_key_func)hmac_streebog256_set_key; ctx->ctx_ptr = &ctx->ctx.streebog256; ctx->length = STREEBOG256_DIGEST_SIZE; break; case GNUTLS_MAC_STREEBOG_512: ctx->update = (update_func)hmac_streebog512_update; ctx->digest = (digest_func)hmac_streebog512_digest; ctx->set_key = (set_key_func)hmac_streebog512_set_key; ctx->ctx_ptr = &ctx->ctx.streebog512; ctx->length = STREEBOG512_DIGEST_SIZE; break; case GNUTLS_MAC_GOST28147_TC26Z_IMIT: ctx->update = (update_func)gost28147_imit_update; ctx->digest = (digest_func)gost28147_imit_digest; ctx->set_key = _wrap_gost28147_imit_set_key_tc26z; ctx->ctx_ptr = &ctx->ctx.gost28147_imit; ctx->length = GOST28147_IMIT_DIGEST_SIZE; break; case GNUTLS_MAC_MAGMA_OMAC: ctx->update = (update_func)cmac_magma_update; ctx->digest = (digest_func)cmac_magma_digest; ctx->set_key = _wrap_cmac_magma_set_key; ctx->ctx_ptr = &ctx->ctx.magma; ctx->length = CMAC64_DIGEST_SIZE; break; case GNUTLS_MAC_KUZNYECHIK_OMAC: ctx->update = (update_func)cmac_kuznyechik_update; ctx->digest = (digest_func)cmac_kuznyechik_digest; ctx->set_key = _wrap_cmac_kuznyechik_set_key; ctx->ctx_ptr = &ctx->ctx.kuznyechik; ctx->length = CMAC128_DIGEST_SIZE; break; #endif case GNUTLS_MAC_UMAC_96: ctx->update = (update_func)umac96_update; ctx->digest = (digest_func)umac96_digest; ctx->set_key = _wrap_umac96_set_key; ctx->set_nonce = (set_nonce_func)umac96_set_nonce; ctx->ctx_ptr = &ctx->ctx.umac96; ctx->length = 12; break; case GNUTLS_MAC_UMAC_128: ctx->update = (update_func)umac128_update; ctx->digest = (digest_func)umac128_digest; ctx->set_key = _wrap_umac128_set_key; ctx->set_nonce = (set_nonce_func)umac128_set_nonce; ctx->ctx_ptr = &ctx->ctx.umac128; ctx->length = 16; break; case GNUTLS_MAC_AES_CMAC_128: ctx->update = (update_func)cmac_aes128_update; ctx->digest = (digest_func)cmac_aes128_digest; ctx->set_key = _wrap_cmac128_set_key; ctx->ctx_ptr = &ctx->ctx.cmac128; ctx->length = CMAC128_DIGEST_SIZE; break; case GNUTLS_MAC_AES_CMAC_256: ctx->update = (update_func)cmac_aes256_update; ctx->digest = (digest_func)cmac_aes256_digest; ctx->set_key = _wrap_cmac256_set_key; ctx->ctx_ptr = &ctx->ctx.cmac256; ctx->length = CMAC128_DIGEST_SIZE; break; case GNUTLS_MAC_AES_GMAC_128: ctx->set_key = _wrap_gmac_aes128_set_key; ctx->set_nonce = _wrap_gmac_set_nonce; ctx->update = _wrap_gmac_update; ctx->digest = _wrap_gmac_digest; ctx->ctx_ptr = &ctx->ctx.gmac; ctx->length = GCM_DIGEST_SIZE; ctx->ctx.gmac.encrypt = (nettle_cipher_func *)aes128_encrypt; break; case GNUTLS_MAC_AES_GMAC_192: ctx->set_key = _wrap_gmac_aes192_set_key; ctx->set_nonce = _wrap_gmac_set_nonce; ctx->update = _wrap_gmac_update; ctx->digest = _wrap_gmac_digest; ctx->ctx_ptr = &ctx->ctx.gmac; ctx->length = GCM_DIGEST_SIZE; ctx->ctx.gmac.encrypt = (nettle_cipher_func *)aes192_encrypt; break; case GNUTLS_MAC_AES_GMAC_256: ctx->set_key = _wrap_gmac_aes256_set_key; ctx->set_nonce = _wrap_gmac_set_nonce; ctx->update = _wrap_gmac_update; ctx->digest = _wrap_gmac_digest; ctx->ctx_ptr = &ctx->ctx.gmac; ctx->length = GCM_DIGEST_SIZE; ctx->ctx.gmac.encrypt = (nettle_cipher_func *)aes256_encrypt; break; default: gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } return 0; } static int wrap_nettle_mac_fast(gnutls_mac_algorithm_t algo, const void *nonce, size_t nonce_size, const void *key, size_t key_size, const void *text, size_t text_size, void *digest) { struct nettle_mac_ctx ctx; int ret; ret = _mac_ctx_init(algo, &ctx); if (ret < 0) return gnutls_assert_val(ret); ctx.set_key(&ctx, key_size, key); if (ctx.set_nonce) { if (nonce == NULL || nonce_size == 0) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ctx.set_nonce(&ctx, nonce_size, nonce); } ctx.update(&ctx, text_size, text); ctx.digest(&ctx, ctx.length, digest); zeroize_temp_key(&ctx, sizeof(ctx)); return 0; } static int wrap_nettle_mac_exists(gnutls_mac_algorithm_t algo) { switch (algo) { case GNUTLS_MAC_MD5: case GNUTLS_MAC_SHA1: case GNUTLS_MAC_SHA224: case GNUTLS_MAC_SHA256: case GNUTLS_MAC_SHA384: case GNUTLS_MAC_SHA512: case GNUTLS_MAC_UMAC_96: case GNUTLS_MAC_UMAC_128: case GNUTLS_MAC_AES_CMAC_128: case GNUTLS_MAC_AES_CMAC_256: case GNUTLS_MAC_AES_GMAC_128: case GNUTLS_MAC_AES_GMAC_192: case GNUTLS_MAC_AES_GMAC_256: #if ENABLE_GOST case GNUTLS_MAC_GOSTR_94: case GNUTLS_MAC_STREEBOG_256: case GNUTLS_MAC_STREEBOG_512: case GNUTLS_MAC_GOST28147_TC26Z_IMIT: case GNUTLS_MAC_MAGMA_OMAC: case GNUTLS_MAC_KUZNYECHIK_OMAC: #endif return 1; default: return 0; } } static int wrap_nettle_mac_init(gnutls_mac_algorithm_t algo, void **_ctx) { struct nettle_mac_ctx *ctx; int ret; ctx = gnutls_calloc(1, sizeof(struct nettle_mac_ctx)); if (ctx == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } ctx->algo = algo; ret = _mac_ctx_init(algo, ctx); if (ret < 0) { gnutls_free(ctx); return gnutls_assert_val(ret); } *_ctx = ctx; return 0; } static void *wrap_nettle_mac_copy(const void *_ctx) { const struct nettle_mac_ctx *ctx = _ctx; struct nettle_mac_ctx *new_ctx; ptrdiff_t off = (uint8_t *)ctx->ctx_ptr - (uint8_t *)(&ctx->ctx); new_ctx = gnutls_calloc(1, sizeof(struct nettle_mac_ctx)); if (new_ctx == NULL) return NULL; memcpy(new_ctx, ctx, sizeof(*ctx)); new_ctx->ctx_ptr = (uint8_t *)&new_ctx->ctx + off; return new_ctx; } static int wrap_nettle_mac_set_key(void *_ctx, const void *key, size_t keylen) { struct nettle_mac_ctx *ctx = _ctx; ctx->set_key(ctx->ctx_ptr, keylen, key); return 0; } static int wrap_nettle_mac_set_nonce(void *_ctx, const void *nonce, size_t noncelen) { struct nettle_mac_ctx *ctx = _ctx; if (ctx->set_nonce == NULL) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); if (nonce == NULL || noncelen == 0) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ctx->set_nonce(ctx->ctx_ptr, noncelen, nonce); return GNUTLS_E_SUCCESS; } static int wrap_nettle_mac_update(void *_ctx, const void *text, size_t textsize) { struct nettle_mac_ctx *ctx = _ctx; ctx->update(ctx->ctx_ptr, textsize, text); return GNUTLS_E_SUCCESS; } static int wrap_nettle_mac_output(void *src_ctx, void *digest, size_t digestsize) { struct nettle_mac_ctx *ctx; ctx = src_ctx; if (digestsize < ctx->length) { gnutls_assert(); return GNUTLS_E_SHORT_MEMORY_BUFFER; } ctx->digest(ctx->ctx_ptr, digestsize, digest); return 0; } static void wrap_nettle_mac_deinit(void *hd) { struct nettle_mac_ctx *ctx = hd; zeroize_temp_key(ctx, sizeof(*ctx)); gnutls_free(ctx); } /* Hash functions */ static int wrap_nettle_hash_update(void *_ctx, const void *text, size_t textsize) { struct nettle_hash_ctx *ctx = _ctx; ctx->update(ctx->ctx_ptr, textsize, text); return GNUTLS_E_SUCCESS; } static void wrap_nettle_hash_deinit(void *hd) { gnutls_free(hd); } static int wrap_nettle_hash_exists(gnutls_digest_algorithm_t algo) { switch (algo) { case GNUTLS_DIG_MD5: case GNUTLS_DIG_SHA1: case GNUTLS_DIG_MD5_SHA1: case GNUTLS_DIG_SHA224: case GNUTLS_DIG_SHA256: case GNUTLS_DIG_SHA384: case GNUTLS_DIG_SHA512: #ifdef NETTLE_SHA3_FIPS202 case GNUTLS_DIG_SHA3_224: case GNUTLS_DIG_SHA3_256: case GNUTLS_DIG_SHA3_384: case GNUTLS_DIG_SHA3_512: #endif case GNUTLS_DIG_SHAKE_128: case GNUTLS_DIG_SHAKE_256: case GNUTLS_DIG_MD2: case GNUTLS_DIG_RMD160: #if ENABLE_GOST case GNUTLS_DIG_GOSTR_94: case GNUTLS_DIG_STREEBOG_256: case GNUTLS_DIG_STREEBOG_512: #endif return 1; default: return 0; } } static void _md5_sha1_update(void *_ctx, size_t len, const uint8_t *data) { struct md5_sha1_ctx *ctx = _ctx; md5_update(&ctx->md5, len, data); sha1_update(&ctx->sha1, len, data); } static void _md5_sha1_digest(void *_ctx, size_t len, uint8_t *digest) { struct md5_sha1_ctx *ctx = _ctx; md5_digest(&ctx->md5, len <= MD5_DIGEST_SIZE ? len : MD5_DIGEST_SIZE, digest); if (len > MD5_DIGEST_SIZE) sha1_digest(&ctx->sha1, len - MD5_DIGEST_SIZE, digest + MD5_DIGEST_SIZE); } static int _ctx_init(gnutls_digest_algorithm_t algo, struct nettle_hash_ctx *ctx) { /* Any FIPS140-2 related enforcement is performed on * gnutls_hash_init() and gnutls_hmac_init() */ switch (algo) { case GNUTLS_DIG_MD5: md5_init(&ctx->ctx.md5); ctx->update = (update_func)md5_update; ctx->digest = (digest_func)md5_digest; ctx->ctx_ptr = &ctx->ctx.md5; ctx->length = MD5_DIGEST_SIZE; break; case GNUTLS_DIG_SHA1: sha1_init(&ctx->ctx.sha1); ctx->update = (update_func)sha1_update; ctx->digest = (digest_func)sha1_digest; ctx->ctx_ptr = &ctx->ctx.sha1; ctx->length = SHA1_DIGEST_SIZE; break; case GNUTLS_DIG_MD5_SHA1: md5_init(&ctx->ctx.md5_sha1.md5); sha1_init(&ctx->ctx.md5_sha1.sha1); ctx->update = (update_func)_md5_sha1_update; ctx->digest = (digest_func)_md5_sha1_digest; ctx->ctx_ptr = &ctx->ctx.md5_sha1; ctx->length = MD5_DIGEST_SIZE + SHA1_DIGEST_SIZE; break; case GNUTLS_DIG_SHA224: sha224_init(&ctx->ctx.sha224); ctx->update = (update_func)sha224_update; ctx->digest = (digest_func)sha224_digest; ctx->ctx_ptr = &ctx->ctx.sha224; ctx->length = SHA224_DIGEST_SIZE; break; case GNUTLS_DIG_SHA256: sha256_init(&ctx->ctx.sha256); ctx->update = (update_func)sha256_update; ctx->digest = (digest_func)sha256_digest; ctx->ctx_ptr = &ctx->ctx.sha256; ctx->length = SHA256_DIGEST_SIZE; break; case GNUTLS_DIG_SHA384: sha384_init(&ctx->ctx.sha384); ctx->update = (update_func)sha384_update; ctx->digest = (digest_func)sha384_digest; ctx->ctx_ptr = &ctx->ctx.sha384; ctx->length = SHA384_DIGEST_SIZE; break; case GNUTLS_DIG_SHA512: sha512_init(&ctx->ctx.sha512); ctx->update = (update_func)sha512_update; ctx->digest = (digest_func)sha512_digest; ctx->ctx_ptr = &ctx->ctx.sha512; ctx->length = SHA512_DIGEST_SIZE; break; #ifdef NETTLE_SHA3_FIPS202 case GNUTLS_DIG_SHA3_224: sha3_224_init(&ctx->ctx.sha3_224); ctx->update = (update_func)sha3_224_update; ctx->digest = (digest_func)sha3_224_digest; ctx->ctx_ptr = &ctx->ctx.sha3_224; ctx->length = SHA3_224_DIGEST_SIZE; break; case GNUTLS_DIG_SHA3_256: sha3_256_init(&ctx->ctx.sha3_256); ctx->update = (update_func)sha3_256_update; ctx->digest = (digest_func)sha3_256_digest; ctx->ctx_ptr = &ctx->ctx.sha3_256; ctx->length = SHA3_256_DIGEST_SIZE; break; case GNUTLS_DIG_SHA3_384: sha3_384_init(&ctx->ctx.sha3_384); ctx->update = (update_func)sha3_384_update; ctx->digest = (digest_func)sha3_384_digest; ctx->ctx_ptr = &ctx->ctx.sha3_384; ctx->length = SHA3_384_DIGEST_SIZE; break; case GNUTLS_DIG_SHA3_512: sha3_512_init(&ctx->ctx.sha3_512); ctx->update = (update_func)sha3_512_update; ctx->digest = (digest_func)sha3_512_digest; ctx->ctx_ptr = &ctx->ctx.sha3_512; ctx->length = SHA3_512_DIGEST_SIZE; break; #endif case GNUTLS_DIG_MD2: md2_init(&ctx->ctx.md2); ctx->update = (update_func)md2_update; ctx->digest = (digest_func)md2_digest; ctx->ctx_ptr = &ctx->ctx.md2; ctx->length = MD2_DIGEST_SIZE; break; #if ENABLE_GOST case GNUTLS_DIG_GOSTR_94: gosthash94cp_init(&ctx->ctx.gosthash94cp); ctx->update = (update_func)gosthash94cp_update; ctx->digest = (digest_func)gosthash94cp_digest; ctx->ctx_ptr = &ctx->ctx.gosthash94cp; ctx->length = GOSTHASH94_DIGEST_SIZE; break; case GNUTLS_DIG_STREEBOG_256: streebog256_init(&ctx->ctx.streebog256); ctx->update = (update_func)streebog256_update; ctx->digest = (digest_func)streebog256_digest; ctx->ctx_ptr = &ctx->ctx.streebog256; ctx->length = STREEBOG256_DIGEST_SIZE; break; case GNUTLS_DIG_STREEBOG_512: streebog512_init(&ctx->ctx.streebog512); ctx->update = (update_func)streebog512_update; ctx->digest = (digest_func)streebog512_digest; ctx->ctx_ptr = &ctx->ctx.streebog512; ctx->length = STREEBOG512_DIGEST_SIZE; break; #endif default: gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } return 0; } static int wrap_nettle_hash_fast(gnutls_digest_algorithm_t algo, const void *text, size_t text_size, void *digest) { struct nettle_hash_ctx ctx; int ret; ret = _ctx_init(algo, &ctx); if (ret < 0) return gnutls_assert_val(ret); if (text_size > 0) { ctx.update(&ctx, text_size, text); } ctx.digest(&ctx, ctx.length, digest); zeroize_temp_key(&ctx, sizeof(ctx)); return 0; } static int wrap_nettle_hash_init(gnutls_digest_algorithm_t algo, void **_ctx) { struct nettle_hash_ctx *ctx; int ret; ctx = gnutls_malloc(sizeof(struct nettle_hash_ctx)); if (ctx == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } ctx->algo = algo; if ((ret = _ctx_init(algo, ctx)) < 0) { gnutls_assert(); gnutls_free(ctx); return ret; } *_ctx = ctx; return 0; } static void *wrap_nettle_hash_copy(const void *_ctx) { const struct nettle_hash_ctx *ctx = _ctx; struct nettle_hash_ctx *new_ctx; ptrdiff_t off = (uint8_t *)ctx->ctx_ptr - (uint8_t *)(&ctx->ctx); new_ctx = gnutls_calloc(1, sizeof(struct nettle_hash_ctx)); if (new_ctx == NULL) return NULL; memcpy(new_ctx, ctx, sizeof(*ctx)); new_ctx->ctx_ptr = (uint8_t *)&new_ctx->ctx + off; return new_ctx; } static int wrap_nettle_hash_output(void *src_ctx, void *digest, size_t digestsize) { struct nettle_hash_ctx *ctx; ctx = src_ctx; if (digestsize < ctx->length) { gnutls_assert(); return GNUTLS_E_SHORT_MEMORY_BUFFER; } ctx->digest(ctx->ctx_ptr, digestsize, digest); return 0; } /* KDF functions based on MAC */ static int wrap_nettle_hkdf_extract(gnutls_mac_algorithm_t mac, const void *key, size_t keysize, const void *salt, size_t saltsize, void *output) { struct nettle_mac_ctx ctx; int ret; ret = _mac_ctx_init(mac, &ctx); if (ret < 0) return gnutls_assert_val(ret); ctx.set_key(&ctx, saltsize, salt); hkdf_extract(&ctx.ctx, ctx.update, ctx.digest, ctx.length, keysize, key, output); zeroize_temp_key(&ctx, sizeof(ctx)); return 0; } static int wrap_nettle_hkdf_expand(gnutls_mac_algorithm_t mac, const void *key, size_t keysize, const void *info, size_t infosize, void *output, size_t length) { struct nettle_mac_ctx ctx; int ret; ret = _mac_ctx_init(mac, &ctx); if (ret < 0) return gnutls_assert_val(ret); /* RFC 5869 2.3: L must be <= 255 * HashLen */ if (length > ctx.length * 255) { return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); } ctx.set_key(&ctx, keysize, key); hkdf_expand(&ctx.ctx, ctx.update, ctx.digest, ctx.length, infosize, info, length, output); zeroize_temp_key(&ctx, sizeof(ctx)); return 0; } static int wrap_nettle_pbkdf2(gnutls_mac_algorithm_t mac, const void *key, size_t keysize, const void *salt, size_t saltsize, unsigned iter_count, void *output, size_t length) { struct nettle_mac_ctx ctx; int ret; ret = _mac_ctx_init(mac, &ctx); if (ret < 0) return gnutls_assert_val(ret); ctx.set_key(&ctx, keysize, key); pbkdf2(&ctx.ctx, ctx.update, ctx.digest, ctx.length, iter_count, saltsize, salt, length, output); zeroize_temp_key(&ctx, sizeof(ctx)); return 0; } gnutls_crypto_mac_st _gnutls_mac_ops = { .init = wrap_nettle_mac_init, .setkey = wrap_nettle_mac_set_key, .setnonce = wrap_nettle_mac_set_nonce, .hash = wrap_nettle_mac_update, .output = wrap_nettle_mac_output, .deinit = wrap_nettle_mac_deinit, .fast = wrap_nettle_mac_fast, .exists = wrap_nettle_mac_exists, .copy = wrap_nettle_mac_copy, }; gnutls_crypto_digest_st _gnutls_digest_ops = { .init = wrap_nettle_hash_init, .hash = wrap_nettle_hash_update, .output = wrap_nettle_hash_output, .deinit = wrap_nettle_hash_deinit, .fast = wrap_nettle_hash_fast, .exists = wrap_nettle_hash_exists, .copy = wrap_nettle_hash_copy, }; /* These names are clashing with nettle's name mangling. */ #undef hkdf_extract #undef hkdf_expand #undef pbkdf2 gnutls_crypto_kdf_st _gnutls_kdf_ops = { .hkdf_extract = wrap_nettle_hkdf_extract, .hkdf_expand = wrap_nettle_hkdf_expand, .pbkdf2 = wrap_nettle_pbkdf2, };