*/
RCSID("$Id$")
-#include <freeradius-devel/util/md5.h>
#include <freeradius-devel/util/atexit.h>
+#include <freeradius-devel/util/md5.h>
+#include <freeradius-devel/util/strerror.h>
#ifdef HAVE_OPENSSL_EVP_H
# include <openssl/hmac.h>
-static _Thread_local HMAC_CTX *md5_hmac_ctx;
+static _Thread_local EVP_MD_CTX *md5_hmac_ctx;
static void _hmac_md5_ctx_free_on_exit(void *arg)
{
- HMAC_CTX_free(arg);
+ EVP_MD_CTX_free(arg);
}
/** Calculate HMAC using OpenSSL's MD5 implementation
* @param inlen length of data stream.
* @param key Pointer to authentication key.
* @param key_len Length of authentication key.
- *
+ * @return
+ * - 0 on success.
+ * - -1 on error.
*/
-void fr_hmac_md5(uint8_t digest[MD5_DIGEST_LENGTH], uint8_t const *in, size_t inlen,
- uint8_t const *key, size_t key_len)
+int fr_hmac_md5(uint8_t digest[MD5_DIGEST_LENGTH], uint8_t const *in, size_t inlen,
+ uint8_t const *key, size_t key_len)
{
- HMAC_CTX *ctx;
+ EVP_MD_CTX *ctx;
+ EVP_PKEY *pkey;
if (unlikely(!md5_hmac_ctx)) {
- ctx = HMAC_CTX_new();
- if (unlikely(!ctx)) return;
+ ctx = EVP_MD_CTX_new();
+ if (unlikely(!ctx)) {
+ fr_strerror_const("Failed allocating EVP_MD_CTX for HMAC-MD5");
+ return -1;
+ }
+ EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_ONESHOT);
fr_atexit_thread_local(md5_hmac_ctx, _hmac_md5_ctx_free_on_exit, ctx);
} else {
ctx = md5_hmac_ctx;
}
-#ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
- /* Since MD5 is not allowed by FIPS, explicitly allow it. */
- HMAC_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
-#endif /* EVP_MD_CTX_FLAG_NON_FIPS_ALLOW */
+ pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, key, key_len);
+ if (unlikely(pkey == NULL)) {
+ fr_strerror_const("Failed allocating pkey for HMAC-MD5");
+ return -1;
+ }
- HMAC_Init_ex(ctx, key, key_len, EVP_md5(), NULL);
- HMAC_Update(ctx, in, inlen);
- HMAC_Final(ctx, digest, NULL);
- HMAC_CTX_reset(ctx);
+ if (unlikely(EVP_DigestSignInit(ctx, NULL, EVP_md5(), NULL, pkey) != 1)) {
+ fr_strerror_const("Failed initialising EVP_MD_CTX for HMAC-MD5");
+ error:
+ EVP_PKEY_free(pkey);
+ return -1;
+ }
+ if (unlikely(EVP_DigestSignUpdate(ctx, in, inlen) != 1)) {
+ fr_strerror_const("Failed ingesting data for HMAC-MD5");
+ goto error;
+ }
+ /*
+ * OpenSSL <= 1.1.1 requires a non-null pointer for len
+ */
+ if (unlikely(EVP_DigestSignFinal(ctx, digest, &(size_t){ 0 }) != 1)) {
+ fr_strerror_const("Failed finalising HMAC-MD5");
+ goto error;
+ }
+
+ EVP_PKEY_free(pkey);
+ EVP_MD_CTX_reset(ctx);
+
+ return 0;
}
#else
/** Calculate HMAC using internal MD5 implementation
* @param inlen length of data stream.
* @param key Pointer to authentication key.
* @param key_len Length of authentication key.
- *
+ * @return
+ * - 0 on success.
+ * - -1 on error.
*/
-void fr_hmac_md5(uint8_t digest[MD5_DIGEST_LENGTH], uint8_t const *in, size_t inlen,
- uint8_t const *key, size_t key_len)
+int fr_hmac_md5(uint8_t digest[MD5_DIGEST_LENGTH], uint8_t const *in, size_t inlen,
+ uint8_t const *key, size_t key_len)
{
fr_md5_ctx_t *ctx;
uint8_t k_ipad[65]; /* inner padding - key XORd with ipad */
fr_md5_final(digest, ctx); /* finish up 2nd pass */
fr_md5_ctx_free(&ctx);
-}
-#endif /* HAVE_OPENSSL_EVP_H */
-
-/*
-Test Vectors (Trailing '\0' of a character string not included in test):
-
- key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
- key_len = 16 bytes
- data = "Hi There"
- data_len = 8 bytes
- digest = 0x9294727a3638bb1c13f48ef8158bfc9d
-
- key = "Jefe"
- data = "what do ya want for nothing?"
- data_len = 28 bytes
- digest = 0x750c783e6ab0b503eaa86e310a5db738
-
- key = 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-
- key_len 16 bytes
- data = 0xDDDDDDDDDDDDDDDDDDDD...
- ..DDDDDDDDDDDDDDDDDDDD...
- ..DDDDDDDDDDDDDDDDDDDD...
- ..DDDDDDDDDDDDDDDDDDDD...
- ..DDDDDDDDDDDDDDDDDDDD
- data_len = 50 bytes
- digest = 0x56be34521d144c88dbb8c733f0e8b3f6
-*/
-
-#ifdef TESTING
-/*
- * cc -DTESTING -I ../include/ hmac.c md5.c -o hmac
- *
- * ./hmac Jefe "what do ya want for nothing?"
- */
-int main(int argc, char **argv)
-{
- uint8_t digest[16];
- char *key;
- int key_len;
- char *text;
- int text_len;
- int i;
-
- key = argv[1];
- key_len = strlen(key);
-
- text = argv[2];
- text_len = strlen(text);
-
- fr_hmac_md5(digest, text, text_len, key, key_len);
-
- for (i = 0; i < 16; i++) {
- printf("%02x", digest[i]);
- }
- printf("\n");
return 0;
}
-
-#endif
+#endif /* HAVE_OPENSSL_EVP_H */
#include <freeradius-devel/util/sha1.h>
#include <freeradius-devel/util/atexit.h>
+#include <freeradius-devel/util/strerror.h>
#ifdef HMAC_SHA1_DATA_PROBLEMS
unsigned int sha1_data_problems = 0;
#ifdef HAVE_OPENSSL_EVP_H
# include <openssl/hmac.h>
-static _Thread_local HMAC_CTX *sha1_hmac_ctx;
+static _Thread_local EVP_MD_CTX *sha1_hmac_ctx;
static void _hmac_sha1_ctx_free_on_exit(void *arg)
{
- HMAC_CTX_free(arg);
+ EVP_MD_CTX_free(arg);
}
/** Calculate HMAC using OpenSSL's SHA1 implementation
* @param inlen length of data stream.
* @param key Pointer to authentication key.
* @param key_len Length of authentication key.
-
+ * @return
+ * - 0 on success.
+ * - -1 on error.
*/
-void fr_hmac_sha1(uint8_t digest[SHA1_DIGEST_LENGTH], uint8_t const *in, size_t inlen,
- uint8_t const *key, size_t key_len)
+int fr_hmac_sha1(uint8_t digest[SHA1_DIGEST_LENGTH], uint8_t const *in, size_t inlen,
+ uint8_t const *key, size_t key_len)
{
- HMAC_CTX *ctx;
+ EVP_MD_CTX *ctx;
+ EVP_PKEY *pkey;
if (unlikely(!sha1_hmac_ctx)) {
- ctx = HMAC_CTX_new();
- if (unlikely(!ctx)) return;
+ ctx = EVP_MD_CTX_new();
+ if (unlikely(!ctx)) {
+ fr_strerror_const("Failed allocating EVP_MD_CTX for HMAC-SHA1");
+ return -1;
+ }
+ EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_ONESHOT);
fr_atexit_thread_local(sha1_hmac_ctx, _hmac_sha1_ctx_free_on_exit, ctx);
} else {
ctx = sha1_hmac_ctx;
}
- HMAC_Init_ex(ctx, key, key_len, EVP_sha1(), NULL);
- HMAC_Update(ctx, in, inlen);
- HMAC_Final(ctx, digest, NULL);
- HMAC_CTX_reset(ctx);
+ pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, key, key_len);
+ if (unlikely(pkey == NULL)) {
+ fr_strerror_const("Failed allocating pkey for HMAC-SHA1");
+ return -1;
+ }
+
+ if (unlikely(EVP_DigestSignInit(ctx, NULL, EVP_sha1(), NULL, pkey) != 1)) {
+ fr_strerror_const("Failed initialising EVP_MD_CTX for HMAC-SHA1");
+ error:
+ EVP_PKEY_free(pkey);
+ return -1;
+ }
+ if (unlikely(EVP_DigestSignUpdate(ctx, in, inlen) != 1)) {
+ fr_strerror_const("Failed ingesting data for HMAC-SHA1");
+ goto error;
+ }
+ /*
+ * OpenSSL <= 1.1.1 requires a non-null pointer for len
+ */
+ if (unlikely(EVP_DigestSignFinal(ctx, digest, &(size_t){ 0 }) != 1)) {
+ fr_strerror_const("Failed finalising HMAC-SHA1");
+ goto error;
+ }
+
+ EVP_PKEY_free(pkey);
+ EVP_MD_CTX_reset(ctx);
+
+ return 0;
}
#else
/** Calculate HMAC using internal SHA1 implementation
* @param inlen length of data stream.
* @param key Pointer to authentication key.
* @param key_len Length of authentication key.
+ * @return
+ * - 0 on success.
+ * - -1 on error.
*/
-void fr_hmac_sha1(uint8_t digest[static SHA1_DIGEST_LENGTH], uint8_t const *in, size_t inlen,
- uint8_t const *key, size_t key_len)
+int fr_hmac_sha1(uint8_t digest[static SHA1_DIGEST_LENGTH], uint8_t const *in, size_t inlen,
+ uint8_t const *key, size_t key_len)
{
fr_sha1_ctx ctx;
uint8_t k_ipad[65]; /* inner padding - key XORd with ipad */
printf("\n");
}
#endif
-}
-#endif /* HAVE_OPENSSL_EVP_H */
-
-/*
-Test Vectors (Trailing '\0' of a character string not included in test):
-
- key = "Jefe"
- data = "what do ya want for nothing?"
- data_len = 28 bytes
- digest = effcdf6ae5eb2fa2d27416d5f184df9c259a7c79
-
- key = 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-
- key_len 16 bytes
- data = 0xDDDDDDDDDDDDDDDDDDDD...
- ..DDDDDDDDDDDDDDDDDDDD...
- ..DDDDDDDDDDDDDDDDDDDD...
- ..DDDDDDDDDDDDDDDDDDDD...
- ..DDDDDDDDDDDDDDDDDDDD
- data_len = 50 bytes
- digest = 0x56be34521d144c88dbb8c733f0e8b3f6
-*/
-
-#ifdef TESTING
-/*
- * cc -DTESTING -I ../include/ hmac.c sha1.c -o hmac
- *
- * ./hmac Jefe "what do ya want for nothing?"
- */
-int main(int argc, char **argv)
-{
- uint8_t digest[20];
- char *key;
- int key_len;
- char *text;
- int text_len;
- int i;
-
- key = argv[1];
- key_len = strlen(key);
-
- text = argv[2];
- text_len = strlen(text);
-
- fr_hmac_sha1(digest, text, text_len, key, key_len);
-
- for (i = 0; i < 20; i++) {
- printf("%02x", digest[i]);
- }
- printf("\n");
-
return 0;
}
-
-#endif
+#endif /* HAVE_OPENSSL_EVP_H */
--- /dev/null
+/*
+ * This 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/** Tests for the internal hmac functions
+ *
+ * @file src/lib/util/hmac_tests.c
+ *
+ * @copyright 2021 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+
+#include <freeradius-devel/util/acutest.h>
+#include <freeradius-devel/util/acutest_helpers.h>
+#include <freeradius-devel/util/md5.h>
+#include <freeradius-devel/util/sha1.h>
+
+/*
+Test Vectors (Trailing '\0' of a character string not included in test):
+
+ key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
+ key_len = 16 bytes
+ data = "Hi There"
+ data_len = 8 bytes
+ digest = 0x9294727a3638bb1c13f48ef8158bfc9d
+
+ key = "Jefe"
+ data = "what do ya want for nothing?"
+ data_len = 28 bytes
+ digest = 0x750c783e6ab0b503eaa86e310a5db738
+
+ key = 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+
+ key_len 16 bytes
+ data = 0xDDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD
+ data_len = 50 bytes
+ digest = 0x56be34521d144c88dbb8c733f0e8b3f6
+*/
+static void test_hmac_md5(void)
+{
+ uint8_t digest[16];
+ uint8_t const *key;
+ int key_len;
+ uint8_t const *text;
+ int text_len;
+
+ /*
+ * Test 1
+ */
+ key = (uint8_t[]){
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x00
+ };
+ key_len = strlen((char const *)key);
+
+ text = (uint8_t const *)"Hi There";
+ text_len = strlen((char const *)text);
+
+ fr_hmac_md5(digest, text, text_len, key, key_len);
+
+ TEST_CHECK_RET(memcmp(digest,
+ (uint8_t[]){
+ 0x92, 0x94, 0x72, 0x7a, 0x36, 0x38, 0xbb, 0x1c,
+ 0x13, 0xf4, 0x8e, 0xf8, 0x15, 0x8b, 0xfc, 0x9d
+ },
+ sizeof(digest)), 0);
+
+ /*
+ * Test 2
+ */
+ key = (uint8_t const *)"Jefe";
+ key_len = strlen((char const *)key);
+
+ text = (uint8_t const *)"what do ya want for nothing?";
+ text_len = strlen((char const *)text);
+
+ fr_hmac_md5(digest, text, text_len, key, key_len);
+
+ TEST_CHECK_RET(memcmp(digest,
+ (uint8_t[]){
+ 0x75, 0x0c, 0x78, 0x3e, 0x6a, 0xb0, 0xb5, 0x03,
+ 0xea, 0xa8, 0x6e, 0x31, 0x0a, 0x5d, 0xb7, 0x38
+ },
+ sizeof(digest)), 0);
+
+ /*
+ * Test 3
+ */
+ key = (uint8_t[]){
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0x00
+ };
+ key_len = strlen((char const *)key);
+
+ text = (uint8_t[]){
+ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
+ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
+ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
+ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
+ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
+ 0x00
+ };
+ text_len = strlen((char const *)text);
+
+ fr_hmac_md5(digest, text, text_len, key, key_len);
+
+ TEST_CHECK_RET(memcmp(digest,
+ (uint8_t[]){
+ 0x56, 0xbe, 0x34, 0x52, 0x1d, 0x14, 0x4c, 0x88,
+ 0xdb, 0xb8, 0xc7, 0x33, 0xf0, 0xe8, 0xb3, 0xf6
+ },
+ sizeof(digest)), 0);
+}
+
+/*
+Test Vectors (Trailing '\0' of a character string not included in test):
+
+ key = "Jefe"
+ data = "what do ya want for nothing?"
+ data_len = 28 bytes
+ digest = 0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79
+
+ key = 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+
+ key_len 16 bytes
+ data = 0xDDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD
+ data_len = 50 bytes
+ digest = 0xd730594d167e35d5956fd8003d0db3d3f46dc7bb
+*/
+static void test_hmac_sha1(void)
+{
+
+ uint8_t digest[20];
+ uint8_t const *key;
+ int key_len;
+ uint8_t const *text;
+ int text_len;
+
+ /*
+ * Test 1
+ */
+ key = (uint8_t const *)"Jefe";
+ key_len = strlen((char const *)key);
+
+ text = (uint8_t const *)"what do ya want for nothing?";
+ text_len = strlen((char const *)text);
+
+ fr_hmac_sha1(digest, text, text_len, key, key_len);
+
+ TEST_CHECK_RET(memcmp(digest,
+ (uint8_t[]){
+ 0xef, 0xfc, 0xdf, 0x6a, 0xe5, 0xeb, 0x2f, 0xa2, 0xd2, 0x74,
+ 0x16, 0xd5, 0xf1, 0x84, 0xdf, 0x9c, 0x25, 0x9a, 0x7c, 0x79
+ },
+ sizeof(digest)), 0);
+
+ /*
+ * Test 2
+ */
+ key = (uint8_t[]){
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0x00
+ };
+ key_len = strlen((char const *)key);
+
+ text = (uint8_t[]){
+ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
+ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
+ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
+ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
+ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
+ 0x00
+ };
+ text_len = strlen((char const *)text);
+
+ fr_hmac_sha1(digest, text, text_len, key, key_len);
+
+ TEST_CHECK_RET(memcmp(digest,
+ (uint8_t[]){
+ 0xd7, 0x30, 0x59, 0x4d, 0x16, 0x7e, 0x35, 0xd5, 0x95, 0x6f,
+ 0xd8, 0x00, 0x3d, 0x0d, 0xb3, 0xd3, 0xf4, 0x6d, 0xc7, 0xbb
+ },
+ sizeof(digest)), 0);
+}
+
+TEST_LIST = {
+ /*
+ * Allocation and management
+ */
+ { "hmac-md5", test_hmac_md5 },
+ { "hmac-sha1", test_hmac_sha1 },
+
+ { NULL }
+};