mirror of
https://github.com/stefanberger/libtpms
synced 2026-08-10 04:57:38 +00:00
WIP: tests: Add test case for KDFa replacement by OpenSSL 'KBKDF'
Implement a KDFa replacement using OpenSSL's KBKDF function. The resulting implementation has a few restrictions compared to the original one. For example, it cannot accept a counter value to be passed in to resume the KDFa as the reference implementation could -- OSSL does not support providing the counter in this becomes problematic with DRBG_Generate where it seems to want to resume with a counter over the long-term. Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
This commit is contained in:
parent
036cb1abd1
commit
42cbf67ebe
1
.gitignore
vendored
1
.gitignore
vendored
@ -52,6 +52,7 @@ Makefile
|
||||
/tests/base64decode
|
||||
/tests/fuzz
|
||||
/tests/freebl_sha1flattensize
|
||||
/tests/kdfa_openssl
|
||||
/tests/kdfe_openssl
|
||||
/tests/nvram_offsets
|
||||
/tests/object_size
|
||||
|
||||
@ -1204,3 +1204,147 @@ out:
|
||||
}
|
||||
|
||||
#endif // USE_OPENSSL_FUNCTIONS_SSKDF
|
||||
|
||||
#if USE_OPENSSL_FUNCTIONS_KBKDF
|
||||
|
||||
UINT16 OSSLCryptKDFa(
|
||||
TPM_ALG_ID hashAlg, // IN: hash algorithm used in HMAC
|
||||
const TPM2B* key, // IN: HMAC key
|
||||
const TPM2B* label, // IN: a label for the KDF
|
||||
const TPM2B* contextU, // IN: context U
|
||||
const TPM2B* contextV, // IN: context V
|
||||
UINT32 sizeInBits, // IN: size of generated key in bits
|
||||
BYTE* keyStream, // OUT: key buffer
|
||||
UINT32* counterInOut, // IN/OUT: caller may provide the iteration
|
||||
// counter for incremental operations to
|
||||
// avoid large intermediate buffers.
|
||||
UINT16 blocks // IN: If non-zero, this is the maximum number
|
||||
// of blocks to be returned, regardless
|
||||
// of sizeInBits
|
||||
)
|
||||
{
|
||||
UINT16 digestSize = CryptHashGetDigestSize(hashAlg);
|
||||
char digestname[16];
|
||||
OSSL_PARAM params[8];
|
||||
OSSL_PARAM *p = params;
|
||||
int use_separator = 0;
|
||||
UINT16 generated = 0;
|
||||
size_t contexts_size;
|
||||
size_t buffer_size;
|
||||
UINT32 counter = 0; // counter value
|
||||
char *buffer; // for contextU+V and key and label
|
||||
size_t offset;
|
||||
EVP_KDF_CTX *ctx;
|
||||
EVP_KDF *kdf;
|
||||
INT16 bytes; // number of bytes to generate
|
||||
const char *name;
|
||||
|
||||
pAssert(key != NULL && keyStream != NULL);
|
||||
|
||||
TPM_DO_SELF_TEST(TPM_ALG_KDF1_SP800_108);
|
||||
|
||||
if(digestSize == 0)
|
||||
return 0;
|
||||
|
||||
if(counterInOut != NULL)
|
||||
counter = *counterInOut;
|
||||
|
||||
/* The TPM2 reference implementation can iterate by calling CryptKDFe multiple
|
||||
* times and allows providing a counter for the next iteration. The
|
||||
* OpenSSL function does not allow this. Therefore:
|
||||
* - This implementation MUST NOT be used with counter != 0. Adjust caller!
|
||||
*/
|
||||
pAssert(counter == 0);
|
||||
/* - This implementation MUST NOT be called blocks != 0 and
|
||||
* blocks * digestSize * 8 != sizeInBits. Better call with blocks = 0!
|
||||
*/
|
||||
pAssert(blocks == 0 || blocks * digestSize * 8 == sizeInBits);
|
||||
/* - This implementation MUST NOT be called for sizeInBits & 7 != 0 since
|
||||
* OpenSSL implementation only allows for multiples of 8.
|
||||
*/
|
||||
pAssert((sizeInBits & 7) == 0);
|
||||
|
||||
// If the size of the request is larger than the numbers will handle,
|
||||
// it is a fatal error.
|
||||
pAssert(((sizeInBits + 7) / 8) <= INT16_MAX);
|
||||
|
||||
// The number of bytes to be generated is the smaller of the sizeInBits bytes or
|
||||
// the number of requested blocks. The number of blocks is the smaller of the
|
||||
// number requested or the number allowed by sizeInBits. A partial block is
|
||||
// a full block.
|
||||
bytes = (blocks > 0) ? blocks * digestSize : (UINT16)BITS_TO_BYTES(sizeInBits);
|
||||
|
||||
name = GetDigestNameByHashAlg(hashAlg);
|
||||
if (!name)
|
||||
return 0;
|
||||
if (strlen(name) >= sizeof(digestname))
|
||||
FAIL(FATAL_ERROR_INTERNAL);
|
||||
strcpy(digestname, name);
|
||||
|
||||
buffer_size = 0;
|
||||
if (contextU)
|
||||
buffer_size += contextU->size;
|
||||
if (contextV)
|
||||
buffer_size += contextV->size;
|
||||
buffer_size += key->size;
|
||||
if (label)
|
||||
buffer_size += label->size;
|
||||
|
||||
buffer = malloc(buffer_size);
|
||||
if (!buffer)
|
||||
return 0;
|
||||
|
||||
kdf = EVP_KDF_fetch(NULL, OSSL_KDF_NAME_KBKDF, NULL);
|
||||
if (!kdf)
|
||||
goto out;
|
||||
|
||||
ctx = EVP_KDF_CTX_new(kdf);
|
||||
if (!ctx)
|
||||
goto out;
|
||||
|
||||
/* fill buffer: 1st contexts; 2nd key; 3rd label */
|
||||
offset = 0;
|
||||
if (contextU) {
|
||||
memcpy(&buffer[offset], contextU->buffer, contextU->size);
|
||||
offset += contextU->size;
|
||||
}
|
||||
if (contextV) {
|
||||
memcpy(&buffer[offset], contextV->buffer, contextV->size);
|
||||
offset += contextV->size;
|
||||
}
|
||||
contexts_size = offset;
|
||||
memcpy(&buffer[contexts_size], key->buffer, key->size);
|
||||
if (label)
|
||||
memcpy(&buffer[contexts_size + key->size], label->buffer, label->size);
|
||||
|
||||
if ((label == NULL) || (label->size == 0)
|
||||
|| (label->buffer[label->size - 1] != 0))
|
||||
use_separator = 1;
|
||||
|
||||
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
|
||||
digestname, 0);
|
||||
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_MAC,
|
||||
"HMAC", 0);
|
||||
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO,
|
||||
buffer, contexts_size);
|
||||
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY,
|
||||
&buffer[contexts_size], key->size);
|
||||
if (label)
|
||||
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT,
|
||||
&buffer[contexts_size + key->size],
|
||||
label->size);
|
||||
*p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_KBKDF_USE_SEPARATOR,
|
||||
&use_separator);
|
||||
*p = OSSL_PARAM_construct_end();
|
||||
if (EVP_KDF_derive(ctx, keyStream, bytes, params) <= 0)
|
||||
goto out;
|
||||
|
||||
generated = bytes;
|
||||
|
||||
out:
|
||||
EVP_KDF_free(kdf);
|
||||
|
||||
return generated;
|
||||
}
|
||||
|
||||
#endif // USE_OPENSSL_FUNCTIONS_KBKDF
|
||||
|
||||
@ -131,4 +131,23 @@ OSSLCryptKDFe(TPM_ALG_ID hashAlg, // IN: hash algorithm used in HMAC
|
||||
);
|
||||
#endif // USE_OPENSSL_FUNCTIONS_SSKDF
|
||||
|
||||
#if USE_OPENSSL_FUNCTIONS_KBKDF
|
||||
LIB_EXPORT UINT16
|
||||
OSSLCryptKDFa(
|
||||
TPM_ALG_ID hashAlg, // IN: hash algorithm used in HMAC
|
||||
const TPM2B* key, // IN: HMAC key
|
||||
const TPM2B* label, // IN: a label for the KDF
|
||||
const TPM2B* contextU, // IN: context U
|
||||
const TPM2B* contextV, // IN: context V
|
||||
UINT32 sizeInBits, // IN: size of generated key in bits
|
||||
BYTE* keyStream, // OUT: key buffer
|
||||
UINT32* counterInOut, // IN/OUT: caller may provide the iteration
|
||||
// counter for incremental operations to
|
||||
// avoid large intermediate buffers.
|
||||
UINT16 blocks // IN: If non-zero, this is the maximum number
|
||||
// of blocks to be returned, regardless
|
||||
// of sizeInBits
|
||||
);
|
||||
#endif // USE_OPENSSL_FUNCTIONS_KBKDF
|
||||
|
||||
#endif /* HELPERS_FP_H */
|
||||
|
||||
@ -57,10 +57,12 @@ if ENABLE_STATIC_TESTS
|
||||
# object_size needs ANY_OBJECT_Marshal which only is accessible with '-static'
|
||||
check_PROGRAMS += \
|
||||
object_size \
|
||||
kdfe_openssl
|
||||
kdfe_openssl \
|
||||
kdfa_openssl
|
||||
TESTS += \
|
||||
object_size \
|
||||
kdfe_openssl
|
||||
kdfe_openssl \
|
||||
kdfa_openssl
|
||||
|
||||
object_size_SOURCES = object_size.c
|
||||
object_size_CFLAGS = $(AM_CFLAGS) \
|
||||
@ -85,6 +87,18 @@ kdfe_openssl_CFLAGS = $(AM_CFLAGS) \
|
||||
-DTPM_POSIX
|
||||
kdfe_openssl_LDFLAGS = $(AM_LDFLAGS)
|
||||
|
||||
kdfa_openssl_SOURCES = kdfa_openssl.c
|
||||
kdfa_openssl_CFLAGS = $(AM_CFLAGS) \
|
||||
-static \
|
||||
-g -ggdb \
|
||||
-I$(top_srcdir)/include/libtpms \
|
||||
-I$(top_srcdir)/src \
|
||||
-I$(top_srcdir)/src/tpm2 \
|
||||
-I$(top_srcdir)/src/tpm2/crypto \
|
||||
-I$(top_srcdir)/src/tpm2/crypto/openssl \
|
||||
-DTPM_POSIX
|
||||
kdfa_openssl_LDFLAGS = $(AM_LDFLAGS)
|
||||
|
||||
endif # ENABLE_STATIC_TESTS
|
||||
endif # WITH_TPM2
|
||||
|
||||
|
||||
76
tests/kdfa_openssl.c
Normal file
76
tests/kdfa_openssl.c
Normal file
@ -0,0 +1,76 @@
|
||||
#if USE_OPENSSL_FUNCTIONS_SSKDF
|
||||
|
||||
#include "Tpm.h"
|
||||
#include "Helpers_fp.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
UINT16 gen1, gen2;
|
||||
TPM2B_LABEL key = {
|
||||
.t.size = 0x20,
|
||||
.t.buffer = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f},
|
||||
};
|
||||
TPM2B_LABEL label = {
|
||||
.t.size = 5,
|
||||
.t.buffer = "label",
|
||||
};
|
||||
TPM2B_LABEL contextU = {
|
||||
.t.size = 6,
|
||||
.t.buffer = "test12",
|
||||
};
|
||||
TPM2B_LABEL contextV = {
|
||||
.t.size = 7,
|
||||
.t.buffer = "test123",
|
||||
};
|
||||
BYTE keyStream1[256] = {0, }, keyStream2[256] = {0, };
|
||||
UINT32 counter1, counter2;
|
||||
const TPM_ALG_ID hashAlgs[] = {
|
||||
TPM_ALG_SHA1,
|
||||
TPM_ALG_SHA256,
|
||||
TPM_ALG_SHA384,
|
||||
TPM_ALG_SHA512
|
||||
};
|
||||
UINT32 sizeInBits;
|
||||
UINT16 blocks;
|
||||
size_t i;
|
||||
|
||||
for (sizeInBits = 0; sizeInBits < 8 * sizeof(keyStream1); sizeInBits += 8) {
|
||||
for (i = 0; i < ARRAY_SIZE(hashAlgs); i++) {
|
||||
counter1 = 0;
|
||||
memset(keyStream1, 0, sizeof(keyStream1));
|
||||
gen1 = CryptKDFa(hashAlgs[i], &key.b, &label.b,
|
||||
&contextU.b, &contextV.b, sizeInBits, keyStream1,
|
||||
&counter1, blocks);
|
||||
|
||||
counter2 = 0;
|
||||
memset(keyStream2, 0, sizeof(keyStream2));
|
||||
gen2 = OSSLCryptKDFa(hashAlgs[i], &key.b, &label.b,
|
||||
&contextU.b, &contextV.b, sizeInBits, keyStream2,
|
||||
&counter2, blocks);
|
||||
|
||||
if (gen1 != gen2 || memcmp(keyStream1, keyStream2, gen1)) {
|
||||
fprintf(stderr, "results are not equal: gen1: %d gen2: %d hash: %d sizeInBits: %d\n",
|
||||
gen1, gen2, hashAlgs[i], sizeInBits);
|
||||
fprintf(stderr, "%02x %02x %02x ... %02x\n",
|
||||
keyStream1[0], keyStream1[1], keyStream1[2], keyStream1[gen1 - 1]);
|
||||
fprintf(stderr, "%02x %02x %02x ... %02x\n",
|
||||
keyStream2[0], keyStream2[1], keyStream2[2], keyStream2[gen2 - 1]);
|
||||
return 1;
|
||||
}
|
||||
fprintf(stdout, "Success with hash %d, sizeInBits %d\n",
|
||||
hashAlgs[i], sizeInBits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
Loading…
Reference in New Issue
Block a user