diff --git a/configure.ac b/configure.ac index b9b99c38de2..b77ba470c26 100644 --- a/configure.ac +++ b/configure.ac @@ -1309,6 +1309,7 @@ AC_CHECK_FUNCS([ \ BIO_sock_non_fatal_error \ CRYPTO_set_mem_functions \ HMAC_CTX_new \ + EVP_MAC_CTX_new \ X509_get0_signature \ ERR_get_error_all \ ]) diff --git a/plugins/s3_auth/aws_auth_v4.cc b/plugins/s3_auth/aws_auth_v4.cc index 3f9aea07777..8950be7a267 100644 --- a/plugins/s3_auth/aws_auth_v4.cc +++ b/plugins/s3_auth/aws_auth_v4.cc @@ -22,13 +22,20 @@ * @see aws_auth_v4.h */ -#include /* strlen() */ -#include /* stoi() */ -#include /* strftime(), time(), gmtime_r() */ -#include /* std::setw */ -#include /* std::stringstream */ -#include /* SHA(), sha256_Update(), SHA256_Final, etc. */ +#include /* strlen() */ +#include /* stoi() */ +#include /* strftime(), time(), gmtime_r() */ +#include /* std::setw */ +#include /* std::stringstream */ + +#include "tscore/ink_config.h" + +#include /* SHA256_DIGEST_LENGTH */ +#include /* EVP_DigestInit_ex, etc.*/ #include /* HMAC() */ +#if defined(HAVE_EVP_MAC_CTX_NEW) +#include /* OSSL_MAC_PARAM_KEY, etc. */ +#endif #ifdef AWS_AUTH_V4_DETAILED_DEBUG_OUTPUT #include @@ -217,30 +224,71 @@ trimWhiteSpaces(const String &s) * Group of static inline helper function for less error prone parameter handling and unit test logging. */ inline static void -sha256Update(SHA256_CTX *ctx, const char *in, size_t inLen) +sha256Update(EVP_MD_CTX *ctx, const char *in, size_t inLen) { - SHA256_Update(ctx, in, inLen); + EVP_DigestUpdate(ctx, in, inLen); #ifdef AWS_AUTH_V4_DETAILED_DEBUG_OUTPUT std::cout << String(in, inLen); #endif } inline static void -sha256Update(SHA256_CTX *ctx, const char *in) +sha256Update(EVP_MD_CTX *ctx, const char *in) { sha256Update(ctx, in, strlen(in)); } inline static void -sha256Update(SHA256_CTX *ctx, const String &in) +sha256Update(EVP_MD_CTX *ctx, const String &in) { sha256Update(ctx, in.c_str(), in.length()); } inline static void -sha256Final(unsigned char hex[SHA256_DIGEST_LENGTH], SHA256_CTX *ctx) +sha256Final(unsigned char hex[SHA256_DIGEST_LENGTH], EVP_MD_CTX *ctx) +{ + EVP_DigestFinal_ex(ctx, hex, nullptr); +} + +static unsigned char * +hmac_sha256(const void *key, int key_len, const unsigned char *data, int data_len, unsigned char *md, unsigned int *md_len) { - SHA256_Final(hex, ctx); +#if defined(HAVE_EVP_MAC_CTX_NEW) + unsigned char *result = nullptr; + + if (EVP_MAC *mac = EVP_MAC_fetch(nullptr, "HMAC", nullptr); mac) { + if (EVP_MAC_CTX *ctx = EVP_MAC_CTX_new(mac); ctx) { + const OSSL_PARAM params[] = { + OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, const_cast(key), key_len), + OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, const_cast(SN_sha256), 0), + OSSL_PARAM_construct_end(), + }; + bool ret = EVP_MAC_CTX_set_params(ctx, params); + + if (ret) { + ret = EVP_MAC_init(ctx); + } + if (ret) { + ret = EVP_MAC_update(ctx, data, data_len); + } + if (ret) { + size_t len; + ret = EVP_MAC_final(ctx, md, &len, SHA256_DIGEST_LENGTH); // Assuming md has enough space as HMAC() does + *md_len = len; + } + if (ret) { + result = md; + } + + EVP_MAC_CTX_free(ctx); + } + EVP_MAC_free(mac); + } + + return result; +#else + return HMAC(EVP_sha256(), key, key_len, data, data_len, md, md_len); +#endif } /** @@ -259,8 +307,13 @@ getPayloadSha256(bool signPayload) return UNSIGNED_PAYLOAD; } - unsigned char payloadHash[SHA256_DIGEST_LENGTH]; - SHA256(reinterpret_cast(""), 0, payloadHash); /* empty content */ + unsigned char payloadHash[SHA256_DIGEST_LENGTH] = {0}; + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + if (EVP_DigestInit_ex(ctx, EVP_sha256(), nullptr)) { + EVP_DigestUpdate(ctx, reinterpret_cast(""), 0); /* empty content */ + EVP_DigestFinal_ex(ctx, payloadHash, nullptr); + } + EVP_MD_CTX_free(ctx); return base16Encode(reinterpret_cast(payloadHash), SHA256_DIGEST_LENGTH); } @@ -285,9 +338,10 @@ getCanonicalRequestSha256Hash(TsInterface &api, bool signPayload, const StringSe int length; const char *str = nullptr; unsigned char canonicalRequestSha256Hash[SHA256_DIGEST_LENGTH]; - SHA256_CTX canonicalRequestSha256Ctx; + EVP_MD_CTX *canonicalRequestSha256Ctx; - SHA256_Init(&canonicalRequestSha256Ctx); + canonicalRequestSha256Ctx = EVP_MD_CTX_new(); + EVP_DigestInit_ex(canonicalRequestSha256Ctx, EVP_sha256(), nullptr); #ifdef AWS_AUTH_V4_DETAILED_DEBUG_OUTPUT std::cout << ""; @@ -295,8 +349,8 @@ getCanonicalRequestSha256Hash(TsInterface &api, bool signPayload, const StringSe /* \n */ str = api.getMethod(&length); - sha256Update(&canonicalRequestSha256Ctx, str, length); - sha256Update(&canonicalRequestSha256Ctx, "\n"); + sha256Update(canonicalRequestSha256Ctx, str, length); + sha256Update(canonicalRequestSha256Ctx, "\n"); /* URI Encoded Canonical URI * \n */ @@ -304,8 +358,8 @@ getCanonicalRequestSha256Hash(TsInterface &api, bool signPayload, const StringSe String path("/"); path.append(str, length); String canonicalUri = canonicalEncode(path, /* isObjectName */ true); - sha256Update(&canonicalRequestSha256Ctx, canonicalUri); - sha256Update(&canonicalRequestSha256Ctx, "\n"); + sha256Update(canonicalRequestSha256Ctx, canonicalUri); + sha256Update(canonicalRequestSha256Ctx, "\n"); /* Sorted Canonical Query String * \n */ @@ -335,8 +389,8 @@ getCanonicalRequestSha256Hash(TsInterface &api, bool signPayload, const StringSe queryStr.append(paramName); queryStr.append("=").append(paramsMap[paramName]); } - sha256Update(&canonicalRequestSha256Ctx, queryStr); - sha256Update(&canonicalRequestSha256Ctx, "\n"); + sha256Update(canonicalRequestSha256Ctx, queryStr); + sha256Update(canonicalRequestSha256Ctx, "\n"); /* Sorted Canonical Headers * \n */ @@ -393,12 +447,12 @@ getCanonicalRequestSha256Hash(TsInterface &api, bool signPayload, const StringSe } for (const auto &it : signedHeadersSet) { - sha256Update(&canonicalRequestSha256Ctx, it); - sha256Update(&canonicalRequestSha256Ctx, ":"); - sha256Update(&canonicalRequestSha256Ctx, headersMap[it]); - sha256Update(&canonicalRequestSha256Ctx, "\n"); + sha256Update(canonicalRequestSha256Ctx, it); + sha256Update(canonicalRequestSha256Ctx, ":"); + sha256Update(canonicalRequestSha256Ctx, headersMap[it]); + sha256Update(canonicalRequestSha256Ctx, "\n"); } - sha256Update(&canonicalRequestSha256Ctx, "\n"); + sha256Update(canonicalRequestSha256Ctx, "\n"); for (const auto &it : signedHeadersSet) { if (!signedHeaders.empty()) { @@ -407,19 +461,20 @@ getCanonicalRequestSha256Hash(TsInterface &api, bool signPayload, const StringSe signedHeaders.append(it); } - sha256Update(&canonicalRequestSha256Ctx, signedHeaders); - sha256Update(&canonicalRequestSha256Ctx, "\n"); + sha256Update(canonicalRequestSha256Ctx, signedHeaders); + sha256Update(canonicalRequestSha256Ctx, "\n"); /* Hex(SHA256Hash() (no new-line char at end) * @TODO support non-empty content, i.e. POST */ String payloadSha256Hash = getPayloadSha256(signPayload); - sha256Update(&canonicalRequestSha256Ctx, payloadSha256Hash); + sha256Update(canonicalRequestSha256Ctx, payloadSha256Hash); /* Hex(SHA256Hash()) */ - sha256Final(canonicalRequestSha256Hash, &canonicalRequestSha256Ctx); + sha256Final(canonicalRequestSha256Hash, canonicalRequestSha256Ctx); #ifdef AWS_AUTH_V4_DETAILED_DEBUG_OUTPUT std::cout << "" << std::endl; #endif + EVP_MD_CTX_free(canonicalRequestSha256Ctx); return base16Encode(reinterpret_cast(canonicalRequestSha256Hash), SHA256_DIGEST_LENGTH); } @@ -663,14 +718,14 @@ getSignature(const char *awsSecret, size_t awsSecretLen, const char *awsRegion, memcpy(key + 4, awsSecret, awsSecretLen); unsigned int len = signatureLen; - if (HMAC(EVP_sha256(), key, keyLen, (unsigned char *)dateTime, dateTimeLen, dateKey, &dateKeyLen) && - HMAC(EVP_sha256(), dateKey, dateKeyLen, (unsigned char *)awsRegion, awsRegionLen, dateRegionKey, &dateRegionKeyLen) && - HMAC(EVP_sha256(), dateRegionKey, dateRegionKeyLen, (unsigned char *)awsService, awsServiceLen, dateRegionServiceKey, - &dateRegionServiceKeyLen) && - HMAC(EVP_sha256(), dateRegionServiceKey, dateRegionServiceKeyLen, reinterpret_cast("aws4_request"), 12, - signingKey, &signingKeyLen) && - HMAC(EVP_sha256(), signingKey, signingKeyLen, (unsigned char *)stringToSign, stringToSignLen, - reinterpret_cast(signature), &len)) { + if (hmac_sha256(key, keyLen, (unsigned char *)dateTime, dateTimeLen, dateKey, &dateKeyLen) && + hmac_sha256(dateKey, dateKeyLen, (unsigned char *)awsRegion, awsRegionLen, dateRegionKey, &dateRegionKeyLen) && + hmac_sha256(dateRegionKey, dateRegionKeyLen, (unsigned char *)awsService, awsServiceLen, dateRegionServiceKey, + &dateRegionServiceKeyLen) && + hmac_sha256(dateRegionServiceKey, dateRegionServiceKeyLen, reinterpret_cast("aws4_request"), 12, + signingKey, &signingKeyLen) && + hmac_sha256(signingKey, signingKeyLen, (unsigned char *)stringToSign, stringToSignLen, + reinterpret_cast(signature), &len)) { return len; } diff --git a/plugins/s3_auth/s3_auth.cc b/plugins/s3_auth/s3_auth.cc index 696fcab279d..580fecb733d 100644 --- a/plugins/s3_auth/s3_auth.cc +++ b/plugins/s3_auth/s3_auth.cc @@ -34,12 +34,16 @@ #include #include +#include "tscore/ink_config.h" + #include #include +#if defined(HAVE_EVP_MAC_CTX_NEW) +#include +#endif #include #include -#include "tscore/ink_config.h" #include "aws_auth_v4.h" @@ -131,6 +135,23 @@ loadRegionMap(StringMap &m, const String &filename) return true; } +/** + * A wrapper function to absorb API difference among OpenSSL versions + */ +#if defined(HAVE_EVP_MAC_CTX_NEW) +inline static int +s3_auth_HMAC_Update(EVP_MAC_CTX *ctx, const unsigned char *data, size_t datalen) +{ + return EVP_MAC_update(ctx, data, datalen); +} +#else +inline static int +s3_auth_HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, size_t datalen) +{ + return HMAC_Update(ctx, data, datalen); +} +#endif + /////////////////////////////////////////////////////////////////////////////// // Cache for the secrets file, to avoid reading / loading them repeatedly on // a reload of remap.config. This gets cached for 60s (not configurable). @@ -799,44 +820,75 @@ S3Request::authorizeV2(S3Config *s3) } // Produce the SHA1 MAC digest -#ifndef HAVE_HMAC_CTX_NEW +#if defined(HAVE_EVP_MAC_CTX_NEW) + EVP_MAC *mac; + EVP_MAC_CTX *ctx; +#elif !defined(HAVE_HMAC_CTX_NEW) HMAC_CTX ctx[1]; #else HMAC_CTX *ctx; #endif + +#if defined(HAVE_EVP_MAC_CTX_NEW) + size_t hmac_len; +#else unsigned int hmac_len; +#endif size_t hmac_b64_len; unsigned char hmac[SHA_DIGEST_LENGTH]; char hmac_b64[SHA_DIGEST_LENGTH * 2]; -#ifndef HAVE_HMAC_CTX_NEW +#if defined(HAVE_EVP_MAC_CTX_NEW) + mac = EVP_MAC_fetch(nullptr, "HMAC", nullptr); + ctx = EVP_MAC_CTX_new(mac); +#elif !defined(HAVE_HMAC_CTX_NEW) HMAC_CTX_init(ctx); #else ctx = HMAC_CTX_new(); #endif + +#if defined(HAVE_EVP_MAC_CTX_NEW) + const OSSL_PARAM params[] = { + OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, const_cast(s3->secret()), s3->secret_len()), + OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, const_cast(SN_sha1), 0), + OSSL_PARAM_construct_end(), + }; + EVP_MAC_CTX_set_params(ctx, params); + EVP_MAC_init(ctx); +#else HMAC_Init_ex(ctx, s3->secret(), s3->secret_len(), EVP_sha1(), nullptr); - HMAC_Update(ctx, (unsigned char *)method, method_len); - HMAC_Update(ctx, reinterpret_cast("\n"), 1); - HMAC_Update(ctx, (unsigned char *)con_md5, con_md5_len); - HMAC_Update(ctx, reinterpret_cast("\n"), 1); - HMAC_Update(ctx, (unsigned char *)con_type, con_type_len); - HMAC_Update(ctx, reinterpret_cast("\n"), 1); - HMAC_Update(ctx, reinterpret_cast(date), date_len); - HMAC_Update(ctx, reinterpret_cast("\n/"), 2); +#endif + + s3_auth_HMAC_Update(ctx, (unsigned char *)method, method_len); + s3_auth_HMAC_Update(ctx, reinterpret_cast("\n"), 1); + s3_auth_HMAC_Update(ctx, (unsigned char *)con_md5, con_md5_len); + s3_auth_HMAC_Update(ctx, reinterpret_cast("\n"), 1); + s3_auth_HMAC_Update(ctx, (unsigned char *)con_type, con_type_len); + s3_auth_HMAC_Update(ctx, reinterpret_cast("\n"), 1); + s3_auth_HMAC_Update(ctx, reinterpret_cast(date), date_len); + s3_auth_HMAC_Update(ctx, reinterpret_cast("\n/"), 2); if (host && host_endp) { - HMAC_Update(ctx, (unsigned char *)host, host_endp - host); - HMAC_Update(ctx, reinterpret_cast("/"), 1); + s3_auth_HMAC_Update(ctx, (unsigned char *)host, host_endp - host); + s3_auth_HMAC_Update(ctx, reinterpret_cast("/"), 1); } - HMAC_Update(ctx, (unsigned char *)path, path_len); + s3_auth_HMAC_Update(ctx, (unsigned char *)path, path_len); if (param) { - HMAC_Update(ctx, reinterpret_cast(";"), 1); // TSUrlHttpParamsGet() does not include ';' - HMAC_Update(ctx, (unsigned char *)param, param_len); + s3_auth_HMAC_Update(ctx, reinterpret_cast(";"), 1); // TSUrlHttpParamsGet() does not include ';' + s3_auth_HMAC_Update(ctx, (unsigned char *)param, param_len); } +#if defined(HAVE_EVP_MAC_CTX_NEW) + EVP_MAC_final(ctx, hmac, &hmac_len, sizeof(hmac)); +#else HMAC_Final(ctx, hmac, &hmac_len); -#ifndef HAVE_HMAC_CTX_NEW +#endif + +#if defined(HAVE_EVP_MAC_CTX_NEW) + EVP_MAC_CTX_free(ctx); + EVP_MAC_free(mac); +#elif !defined(HAVE_HMAC_CTX_NEW) HMAC_CTX_cleanup(ctx); #else HMAC_CTX_free(ctx);