mirror of
https://github.com/curl/curl.git
synced 2026-07-24 12:37:20 +03:00
sha512_256: add support for GnuTLS and OpenSSL
This is a follow-up for PR #12897. Add support for SHA-512/256 digest calculation by TLS backends. Currently only OpenSSL and GnuTLS (actually, nettle) support SHA-512/256. Closes #13070
This commit is contained in:
parent
1e517e9f5c
commit
05268cf801
1 changed files with 268 additions and 27 deletions
|
|
@ -29,6 +29,211 @@
|
|||
#include "curl_sha512_256.h"
|
||||
#include "warnless.h"
|
||||
|
||||
/* The recommended order of the TLS backends:
|
||||
* * OpenSSL
|
||||
* * GnuTLS
|
||||
* * wolfSSL
|
||||
* * Schannel SSPI
|
||||
* * SecureTransport (Darwin)
|
||||
* * mbedTLS
|
||||
* * BearSSL
|
||||
* * rustls
|
||||
* Skip the backend if it does not support the required algorithm */
|
||||
|
||||
#if defined(USE_OPENSSL)
|
||||
# include <openssl/opensslv.h>
|
||||
# if (!defined(LIBRESSL_VERSION_NUMBER) && \
|
||||
defined(OPENSSL_VERSION_NUMBER) && \
|
||||
(OPENSSL_VERSION_NUMBER >= 0x10100010L)) || \
|
||||
(defined(LIBRESSL_VERSION_NUMBER) && \
|
||||
(LIBRESSL_VERSION_NUMBER >= 0x3080000fL))
|
||||
# include <openssl/opensslconf.h>
|
||||
# if !defined(OPENSSL_NO_SHA) && !defined(OPENSSL_NO_SHA512)
|
||||
# include <openssl/evp.h>
|
||||
# define USE_OPENSSL_SHA512_256 1
|
||||
# define HAS_SHA512_256_IMPLEMENTATION 1
|
||||
# endif
|
||||
# endif
|
||||
#endif /* USE_OPENSSL */
|
||||
|
||||
|
||||
#if !defined(HAS_SHA512_256_IMPLEMENTATION) && defined(USE_GNUTLS)
|
||||
# include <nettle/sha.h>
|
||||
# if defined(SHA512_256_DIGEST_SIZE)
|
||||
# define USE_GNUTLS_SHA512_256 1
|
||||
# define HAS_SHA512_256_IMPLEMENTATION 1
|
||||
# endif
|
||||
#endif /* ! HAS_SHA512_256_IMPLEMENTATION && USE_GNUTLS */
|
||||
|
||||
#if defined(USE_OPENSSL_SHA512_256)
|
||||
|
||||
/* OpenSSL does not provide macros for SHA-512/256 sizes */
|
||||
|
||||
/**
|
||||
* Size of the SHA-512/256 single processing block in bytes.
|
||||
*/
|
||||
#define SHA512_256_BLOCK_SIZE 128
|
||||
|
||||
/**
|
||||
* Size of the SHA-512/256 resulting digest in bytes.
|
||||
* This is the final digest size, not intermediate hash.
|
||||
*/
|
||||
#define SHA512_256_DIGEST_SIZE SHA512_256_DIGEST_LENGTH
|
||||
|
||||
/**
|
||||
* Context type used for SHA-512/256 calculations
|
||||
*/
|
||||
typedef EVP_MD_CTX *Curl_sha512_256_ctx;
|
||||
|
||||
/**
|
||||
* Initialise structure for SHA-512/256 calculation.
|
||||
*
|
||||
* @param context the calculation context
|
||||
* @return CURLE_OK if succeed,
|
||||
* error code otherwise
|
||||
*/
|
||||
static CURLcode
|
||||
Curl_sha512_256_init(void *context)
|
||||
{
|
||||
Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context;
|
||||
|
||||
*ctx = EVP_MD_CTX_create();
|
||||
if(!*ctx)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
if(EVP_DigestInit_ex(*ctx, EVP_sha512_256(), NULL)) {
|
||||
/* Check whether the header and this file use the same numbers */
|
||||
DEBUGASSERT(EVP_MD_CTX_size(*ctx) == SHA512_256_DIGEST_SIZE);
|
||||
/* Check whether the block size is correct */
|
||||
DEBUGASSERT(EVP_MD_CTX_block_size(*ctx) == SHA512_256_BLOCK_SIZE);
|
||||
|
||||
return CURLE_OK; /* Success */
|
||||
}
|
||||
|
||||
/* Cleanup */
|
||||
EVP_MD_CTX_destroy(*ctx);
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process portion of bytes.
|
||||
*
|
||||
* @param context the calculation context
|
||||
* @param data bytes to add to hash
|
||||
* @return CURLE_OK if succeed,
|
||||
* error code otherwise
|
||||
*/
|
||||
static CURLcode
|
||||
Curl_sha512_256_update(void *context,
|
||||
const unsigned char *data,
|
||||
size_t length)
|
||||
{
|
||||
Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context;
|
||||
|
||||
if(!EVP_DigestUpdate(*ctx, data, length))
|
||||
return CURLE_SSL_CIPHER;
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finalise SHA-512/256 calculation, return digest.
|
||||
*
|
||||
* @param context the calculation context
|
||||
* @param[out] digest set to the hash, must be #SHA512_256_DIGEST_SIZE bytes
|
||||
* @return CURLE_OK if succeed,
|
||||
* error code otherwise
|
||||
*/
|
||||
static CURLcode
|
||||
Curl_sha512_256_finish(unsigned char *digest,
|
||||
void *context)
|
||||
{
|
||||
CURLcode ret;
|
||||
Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context;
|
||||
|
||||
ret = EVP_DigestFinal_ex(*ctx, digest, NULL) ? CURLE_OK : CURLE_SSL_CIPHER;
|
||||
|
||||
EVP_MD_CTX_destroy(*ctx);
|
||||
*ctx = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#elif defined(USE_GNUTLS_SHA512_256)
|
||||
|
||||
/**
|
||||
* Context type used for SHA-512/256 calculations
|
||||
*/
|
||||
typedef struct sha512_256_ctx Curl_sha512_256_ctx;
|
||||
|
||||
/**
|
||||
* Initialise structure for SHA-512/256 calculation.
|
||||
*
|
||||
* @param context the calculation context
|
||||
* @return always CURLE_OK
|
||||
*/
|
||||
static CURLcode
|
||||
Curl_sha512_256_init(void *context)
|
||||
{
|
||||
Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context;
|
||||
|
||||
/* Check whether the header and this file use the same numbers */
|
||||
DEBUGASSERT(SHA512_256_DIGEST_LENGTH == SHA512_256_DIGEST_SIZE);
|
||||
|
||||
sha512_256_init(ctx);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process portion of bytes.
|
||||
*
|
||||
* @param context the calculation context
|
||||
* @param data bytes to add to hash
|
||||
* @param length number of bytes in @a data
|
||||
* @return always CURLE_OK
|
||||
*/
|
||||
static CURLcode
|
||||
Curl_sha512_256_update(void *context,
|
||||
const unsigned char *data,
|
||||
size_t length)
|
||||
{
|
||||
Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context;
|
||||
|
||||
DEBUGASSERT((data != NULL) || (length == 0));
|
||||
|
||||
sha512_256_update(ctx, length, (const uint8_t *)data);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finalise SHA-512/256 calculation, return digest.
|
||||
*
|
||||
* @param context the calculation context
|
||||
* @param[out] digest set to the hash, must be #SHA512_256_DIGEST_SIZE bytes
|
||||
* @return always CURLE_OK
|
||||
*/
|
||||
static CURLcode
|
||||
Curl_sha512_256_finish(unsigned char *digest,
|
||||
void *context)
|
||||
{
|
||||
Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context;
|
||||
|
||||
sha512_256_digest(ctx, (size_t)SHA512_256_DIGEST_SIZE, (uint8_t *)digest);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#else /* No system or TLS backend SHA-512/256 implementation available */
|
||||
|
||||
/* Use local implementation */
|
||||
#define HAS_SHA512_256_IMPLEMENTATION 1
|
||||
|
||||
/* ** This implementation of SHA-512/256 hash calculation was originally ** *
|
||||
* ** written by Evgeny Grin (Karlson2k) for GNU libmicrohttpd. ** *
|
||||
* ** The author ported the code to libcurl. The ported code is provided ** *
|
||||
|
|
@ -130,7 +335,7 @@ MHDx_rotr64(curl_uint64_t value, unsigned int bits)
|
|||
#define SHA512_256_HASH_SIZE_WORDS 8
|
||||
|
||||
/**
|
||||
* Size of the SHA-512/256 resulting digest in bytes.
|
||||
* Size of the SHA-512/256 resulting digest in words.
|
||||
* This is the final digest size, not intermediate hash.
|
||||
*/
|
||||
#define SHA512_256_DIGEST_SIZE_WORDS (SHA512_256_HASH_SIZE_WORDS / 2)
|
||||
|
|
@ -161,7 +366,7 @@ MHDx_rotr64(curl_uint64_t value, unsigned int bits)
|
|||
/**
|
||||
* SHA-512/256 calculation context
|
||||
*/
|
||||
struct Sha512_256Ctx
|
||||
struct mhdx_sha512_256ctx
|
||||
{
|
||||
/**
|
||||
* Intermediate hash value. The variable is properly aligned. Smart
|
||||
|
|
@ -186,6 +391,11 @@ struct Sha512_256Ctx
|
|||
curl_uint64_t count_bits_hi;
|
||||
};
|
||||
|
||||
/**
|
||||
* Context type used for SHA-512/256 calculations
|
||||
*/
|
||||
typedef struct mhdx_sha512_256ctx Curl_sha512_256_ctx;
|
||||
|
||||
|
||||
/**
|
||||
* Initialise structure for SHA-512/256 calculation.
|
||||
|
|
@ -196,7 +406,7 @@ struct Sha512_256Ctx
|
|||
static CURLcode
|
||||
MHDx_sha512_256_init(void *context)
|
||||
{
|
||||
struct Sha512_256Ctx *const ctx = (struct Sha512_256Ctx *) context;
|
||||
struct mhdx_sha512_256ctx *const ctx = (struct mhdx_sha512_256ctx *) context;
|
||||
|
||||
/* Check whether the header and this file use the same numbers */
|
||||
DEBUGASSERT(SHA512_256_DIGEST_LENGTH == SHA512_256_DIGEST_SIZE);
|
||||
|
|
@ -393,21 +603,22 @@ MHDx_sha512_256_transform(curl_uint64_t H[SHA512_256_HASH_SIZE_WORDS],
|
|||
* @param context the calculation context
|
||||
* @param data bytes to add to hash
|
||||
* @param length number of bytes in @a data
|
||||
* @return always CURLE_OK
|
||||
*/
|
||||
static void
|
||||
static CURLcode
|
||||
MHDx_sha512_256_update(void *context,
|
||||
const unsigned char *data,
|
||||
unsigned int length)
|
||||
size_t length)
|
||||
{
|
||||
unsigned int bytes_have; /**< Number of bytes in the context buffer */
|
||||
struct Sha512_256Ctx *const ctx = (struct Sha512_256Ctx *) context;
|
||||
struct mhdx_sha512_256ctx *const ctx = (struct mhdx_sha512_256ctx *)context;
|
||||
/* the void pointer here is required to mute Intel compiler warning */
|
||||
void *const ctx_buf = ctx->buffer;
|
||||
|
||||
DEBUGASSERT((data != NULL) || (length == 0));
|
||||
|
||||
if(0 == length)
|
||||
return; /* Shortcut, do nothing */
|
||||
return CURLE_OK; /* Shortcut, do nothing */
|
||||
|
||||
/* Note: (count & (SHA512_256_BLOCK_SIZE-1))
|
||||
equals (count % SHA512_256_BLOCK_SIZE) for this block size. */
|
||||
|
|
@ -446,6 +657,8 @@ MHDx_sha512_256_update(void *context,
|
|||
to the buffer. */
|
||||
memcpy(((unsigned char *) ctx_buf) + bytes_have, data, length);
|
||||
}
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -466,12 +679,13 @@ MHDx_sha512_256_update(void *context,
|
|||
*
|
||||
* @param context the calculation context
|
||||
* @param[out] digest set to the hash, must be #SHA512_256_DIGEST_SIZE bytes
|
||||
* @return always CURLE_OK
|
||||
*/
|
||||
static void
|
||||
static CURLcode
|
||||
MHDx_sha512_256_finish(unsigned char *digest,
|
||||
void *context)
|
||||
{
|
||||
struct Sha512_256Ctx *const ctx = (struct Sha512_256Ctx *) context;
|
||||
struct mhdx_sha512_256ctx *const ctx = (struct mhdx_sha512_256ctx *)context;
|
||||
curl_uint64_t num_bits; /**< Number of processed bits */
|
||||
unsigned int bytes_have; /**< Number of bytes in the context buffer */
|
||||
/* the void pointer here is required to mute Intel compiler warning */
|
||||
|
|
@ -538,9 +752,18 @@ MHDx_sha512_256_finish(unsigned char *digest,
|
|||
MHDX_PUT_64BIT_BE((digest + 3 * SHA512_256_BYTES_IN_WORD), ctx->H[3]);
|
||||
|
||||
/* Erase potentially sensitive data. */
|
||||
memset(ctx, 0, sizeof(struct Sha512_256Ctx));
|
||||
memset(ctx, 0, sizeof(struct mhdx_sha512_256ctx));
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* Map to the local implementation */
|
||||
#define Curl_sha512_256_init MHDx_sha512_256_init
|
||||
#define Curl_sha512_256_update MHDx_sha512_256_update
|
||||
#define Curl_sha512_256_finish MHDx_sha512_256_finish
|
||||
|
||||
#endif /* Local SHA-512/256 code */
|
||||
|
||||
|
||||
/**
|
||||
* Compute SHA-512/256 hash for the given data in one function call
|
||||
|
|
@ -553,35 +776,54 @@ CURLcode
|
|||
Curl_sha512_256it(unsigned char *output, const unsigned char *input,
|
||||
size_t input_size)
|
||||
{
|
||||
struct Sha512_256Ctx ctx;
|
||||
static const unsigned int max_step_size = (unsigned int)(-1);
|
||||
Curl_sha512_256_ctx ctx;
|
||||
CURLcode res;
|
||||
|
||||
(void) MHDx_sha512_256_init(&ctx); /* Always succeed */
|
||||
res = Curl_sha512_256_init(&ctx);
|
||||
if(res != CURLE_OK)
|
||||
return res;
|
||||
|
||||
while(input_size >= max_step_size) {
|
||||
MHDx_sha512_256_update(&ctx, (const void *) input, max_step_size);
|
||||
input += max_step_size;
|
||||
input_size -= max_step_size;
|
||||
res = Curl_sha512_256_update(&ctx, (const void *) input, input_size);
|
||||
|
||||
if(res != CURLE_OK) {
|
||||
(void) Curl_sha512_256_finish(output, &ctx);
|
||||
return res;
|
||||
}
|
||||
MHDx_sha512_256_update(&ctx, (const void *) input,
|
||||
curlx_uztoui(input_size));
|
||||
|
||||
MHDx_sha512_256_finish(output, &ctx);
|
||||
|
||||
return CURLE_OK;
|
||||
return Curl_sha512_256_finish(output, &ctx);
|
||||
}
|
||||
|
||||
/* Wrapper function, takes 'unsigned int' as length type, returns void */
|
||||
static void
|
||||
Curl_sha512_256_update_i(void *context,
|
||||
const unsigned char *data,
|
||||
unsigned int length)
|
||||
{
|
||||
/* Hypothetically the function may fail, but assume it does not */
|
||||
(void) Curl_sha512_256_update(context, data, length);
|
||||
}
|
||||
|
||||
/* Wrapper function, returns void */
|
||||
static void
|
||||
Curl_sha512_256_finish_v(unsigned char *result,
|
||||
void *context)
|
||||
{
|
||||
/* Hypothetically the function may fail, but assume it does not */
|
||||
(void) Curl_sha512_256_finish(result, context);
|
||||
}
|
||||
|
||||
/* Wrapper function, takes 'unsigned int' as length type, returns void */
|
||||
|
||||
const struct HMAC_params Curl_HMAC_SHA512_256[] = {
|
||||
{
|
||||
/* Initialize context procedure. */
|
||||
MHDx_sha512_256_init,
|
||||
Curl_sha512_256_init,
|
||||
/* Update context with data. */
|
||||
MHDx_sha512_256_update,
|
||||
Curl_sha512_256_update_i,
|
||||
/* Get final result procedure. */
|
||||
MHDx_sha512_256_finish,
|
||||
Curl_sha512_256_finish_v,
|
||||
/* Context structure size. */
|
||||
sizeof(struct Sha512_256Ctx),
|
||||
sizeof(Curl_sha512_256_ctx),
|
||||
/* Maximum key length (bytes). */
|
||||
SHA512_256_BLOCK_SIZE,
|
||||
/* Result length (bytes). */
|
||||
|
|
@ -589,5 +831,4 @@ const struct HMAC_params Curl_HMAC_SHA512_256[] = {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
#endif /* !CURL_DISABLE_DIGEST_AUTH && !CURL_DISABLE_SHA512_256 */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue