/* * Copyright (C) 2020 Red Hat, Inc. * * Author: Daiki Ueno * * This file is part of GnuTLS. * * The GnuTLS 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 * */ #include "config.h" #include #include #include #include #include "utils.h" #define MAX_BUF 1024 static gnutls_fips140_context_t fips_context; static gnutls_fips140_operation_state_t fips_state; #define FIPS_PUSH_CONTEXT() do { \ if (gnutls_fips140_mode_enabled()) { \ ret = gnutls_fips140_push_context(fips_context); \ if (ret < 0) { \ fail("gnutls_fips140_push_context failed\n"); \ } \ } \ } while (0) #define FIPS_POP_CONTEXT(state) do { \ if (gnutls_fips140_mode_enabled()) { \ ret = gnutls_fips140_pop_context(); \ if (ret < 0) { \ fail("gnutls_fips140_context_pop failed\n"); \ } \ fips_state = gnutls_fips140_get_operation_state(fips_context); \ if (fips_state != GNUTLS_FIPS140_OP_ ## state) { \ fail("operation state is not " # state " (%d)\n", \ fips_state); \ } \ } \ } while (0) static void test_hkdf(gnutls_mac_algorithm_t mac, const char *ikm_hex, const char *salt_hex, const char *info_hex, size_t length, const char *prk_hex, const char *okm_hex) { gnutls_datum_t hex; gnutls_datum_t ikm; gnutls_datum_t salt; gnutls_datum_t info; gnutls_datum_t prk; gnutls_datum_t okm; uint8_t buf[MAX_BUF]; int ret; success("HKDF test with %s\n", gnutls_mac_get_name(mac)); /* Test HKDF-Extract */ hex.data = (void *)ikm_hex; hex.size = strlen(ikm_hex); assert(gnutls_hex_decode2(&hex, &ikm) >= 0); hex.data = (void *)salt_hex; hex.size = strlen(salt_hex); assert(gnutls_hex_decode2(&hex, &salt) >= 0); FIPS_PUSH_CONTEXT(); assert(gnutls_hkdf_extract(mac, &ikm, &salt, buf) >= 0); FIPS_POP_CONTEXT(NOT_APPROVED); gnutls_free(ikm.data); gnutls_free(salt.data); prk.data = buf; prk.size = strlen(prk_hex) / 2; assert(gnutls_hex_encode2(&prk, &hex) >= 0); if (strcmp((char *)hex.data, prk_hex)) fail("prk doesn't match: %s != %s\n", (char *)hex.data, prk_hex); gnutls_free(hex.data); /* Test HKDF-Expand */ hex.data = (void *)info_hex; hex.size = strlen(info_hex); assert(gnutls_hex_decode2(&hex, &info) >= 0); FIPS_PUSH_CONTEXT(); assert(gnutls_hkdf_expand(mac, &prk, &info, buf, gnutls_hmac_get_len(mac) * 256) == GNUTLS_E_INVALID_REQUEST); FIPS_POP_CONTEXT(ERROR); FIPS_PUSH_CONTEXT(); assert(gnutls_hkdf_expand(mac, &prk, &info, buf, length) >= 0); FIPS_POP_CONTEXT(NOT_APPROVED); gnutls_free(info.data); okm.data = buf; okm.size = strlen(okm_hex) / 2; assert(gnutls_hex_encode2(&okm, &hex) >= 0); if (strcmp((char *)hex.data, okm_hex)) fail("okm doesn't match: %s != %s\n", (char *)hex.data, okm_hex); gnutls_free(hex.data); } static void test_pbkdf2(gnutls_mac_algorithm_t mac, const char *ikm_hex, const char *salt_hex, unsigned iter_count, size_t length, const char *okm_hex) { gnutls_datum_t hex; gnutls_datum_t ikm; gnutls_datum_t salt; gnutls_datum_t okm; uint8_t buf[MAX_BUF]; int ret; success("PBKDF2 test with %s\n", gnutls_mac_get_name(mac)); hex.data = (void *)ikm_hex; hex.size = strlen(ikm_hex); assert(gnutls_hex_decode2(&hex, &ikm) >= 0); hex.data = (void *)salt_hex; hex.size = strlen(salt_hex); assert(gnutls_hex_decode2(&hex, &salt) >= 0); FIPS_PUSH_CONTEXT(); assert(gnutls_pbkdf2(mac, &ikm, &salt, iter_count, buf, length) >= 0); FIPS_POP_CONTEXT(APPROVED); gnutls_free(ikm.data); gnutls_free(salt.data); okm.data = buf; okm.size = length; assert(gnutls_hex_encode2(&okm, &hex) >= 0); if (strcmp((char *)hex.data, okm_hex)) fail("okm doesn't match: %s != %s\n", (char *)hex.data, okm_hex); gnutls_free(hex.data); } void doit(void) { assert(gnutls_fips140_context_init(&fips_context) >= 0); /* Test vector from RFC 5869. More thorough testing is done * in nettle. */ test_hkdf(GNUTLS_MAC_SHA256, "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b" "0b0b0b0b0b0b", "000102030405060708090a0b0c", "f0f1f2f3f4f5f6f7f8f9", 42, "077709362c2e32df0ddc3f0dc47bba63" "90b6c73bb50f9c3122ec844ad7c2b3e5", "3cb25f25faacd57a90434f64d0362f2a" "2d2d0a90cf1a5a4c5db02d56ecc4c5bf" "34007208d5b887185865"); /* Test vector from RFC 6070. More thorough testing is done * in nettle. */ test_pbkdf2(GNUTLS_MAC_SHA1, "70617373776f7264", /* "password" */ "73616c74", /* "salt" */ 4096, 20, "4b007901b765489abead49d926f721d065a429c1"); gnutls_fips140_context_deinit(fips_context); }