diff mbox series

[v3,6/7] tcgbios: Add test cases and test script to run them

Message ID 20210709025313.674287-7-stefanb@linux.vnet.ibm.com
State Superseded
Headers show
Series tcgbios: Use the proper hashes for the TPM 2 PCR banks | expand

Commit Message

Stefan Berger July 9, 2021, 2:53 a.m. UTC
From: Stefan Berger <stefanb@linux.ibm.com>

Add test cases for sha1, sha256, sha384, and sha512 and a test script
to run the test cases.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
---
 lib/libtpm/sha.c      | 26 +++++++++++++++++++
 lib/libtpm/sha256.c   | 25 +++++++++++++++++++
 lib/libtpm/sha512.c   | 32 ++++++++++++++++++++++++
 lib/libtpm/sha_test.h | 58 +++++++++++++++++++++++++++++++++++++++++++
 lib/libtpm/test.sh    | 29 ++++++++++++++++++++++
 5 files changed, 170 insertions(+)
 create mode 100644 lib/libtpm/sha_test.h
 create mode 100755 lib/libtpm/test.sh

Comments

Alexey Kardashevskiy July 9, 2021, 6:02 a.m. UTC | #1
On 09/07/2021 12:53, Stefan Berger wrote:
> From: Stefan Berger <stefanb@linux.ibm.com>
> 
> Add test cases for sha1, sha256, sha384, and sha512 and a test script
> to run the test cases.
> 
> Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
> ---
>   lib/libtpm/sha.c      | 26 +++++++++++++++++++
>   lib/libtpm/sha256.c   | 25 +++++++++++++++++++
>   lib/libtpm/sha512.c   | 32 ++++++++++++++++++++++++
>   lib/libtpm/sha_test.h | 58 +++++++++++++++++++++++++++++++++++++++++++
>   lib/libtpm/test.sh    | 29 ++++++++++++++++++++++
>   5 files changed, 170 insertions(+)
>   create mode 100644 lib/libtpm/sha_test.h
>   create mode 100755 lib/libtpm/test.sh
> 
> diff --git a/lib/libtpm/sha.c b/lib/libtpm/sha.c
> index 43de658..6e8b19b 100644
> --- a/lib/libtpm/sha.c
> +++ b/lib/libtpm/sha.c
> @@ -203,3 +203,29 @@ void sha1(const uint8_t *data, uint32_t length, uint8_t *hash)
>   	sha1_do(&ctx, data, length);
>   	memcpy(hash, &ctx.h[0], 20);
>   }
> +
> +#ifdef MAIN
> +
> +#include "sha_test.h"
> +
> +int main(void)
> +{
> +	TESTVECTORS(data);
> +	uint8_t hash[20];
> +	char input[64];
> +	int err = 0;
> +	size_t i;
> +
> +	for (i = 0; data[i]; i++)
> +		err |= test_hash(sha1, hash, sizeof(hash),
> +				 data[i], strlen(data[i]),
> +				 SHA1);
> +
> +	memset(input, 'a', sizeof(input));
> +	for (i = 50; i < sizeof(input); i++)


Why 50?


> +		err |= test_hash(sha1, hash, sizeof(hash),
> +				 input, i, SHA1);
> +
> +	return err;
> +}
> +#endif
> diff --git a/lib/libtpm/sha256.c b/lib/libtpm/sha256.c
> index 1a0aa9a..c921ff5 100644
> --- a/lib/libtpm/sha256.c
> +++ b/lib/libtpm/sha256.c
> @@ -218,3 +218,28 @@ void sha256(const uint8_t *data, uint32_t length, uint8_t *hash)
>   	sha256_do(&ctx, data, length);
>   	memcpy(hash, ctx.h, sizeof(ctx.h));
>   }
> +
> +#ifdef MAIN
> +
> +#include "sha_test.h"
> +
> +int main(void)
> +{
> +	TESTVECTORS(data);
> +	uint8_t hash[32];
> +	char input[64];
> +	int err = 0;
> +	size_t i;
> +
> +	for (i = 0; data[i]; i++)
> +		err |= test_hash(sha256, hash, sizeof(hash),
> +				 data[i], strlen(data[i]),
> +				 SHA256);
> +
> +	memset(input, 'a', sizeof(input));
> +	for (i = 50; i < sizeof(input); i++)

Why 50?


> +		err |= test_hash(sha256, hash, sizeof(hash), input, i, SHA256);
> +
> +	return err;
> +}
> +#endif
> diff --git a/lib/libtpm/sha512.c b/lib/libtpm/sha512.c
> index f9267ef..9e856ea 100644
> --- a/lib/libtpm/sha512.c
> +++ b/lib/libtpm/sha512.c
> @@ -247,3 +247,35 @@ void sha512(const uint8_t *data, uint32_t length, uint8_t *hash)
>   	sha512_do(&ctx, data, length);
>   	memcpy(hash, ctx.h, sizeof(ctx.h));
>   }
> +
> +
> +#ifdef MAIN
> +
> +#include "sha_test.h"
> +
> +int main(void)
> +{
> +	TESTVECTORS(data);
> +	uint8_t hash[64];
> +	char input[128];
> +	int err = 0;
> +	size_t i;
> +
> +	for (i = 0; data[i]; i++) {
> +		err |= test_hash(sha384, hash, 48,

Uff. Why 2 separate tests for 48 and sizeof(hash) here but everywhere 
else it is just sizeof(hash)?



> +				 data[i], strlen(data[i]),
> +				 SHA384);
> +		err |= test_hash(sha512, hash, sizeof(hash),
> +				 data[i], strlen(data[i]),
> +				 SHA512);
> +	}
> +
> +	memset(input, 'a', sizeof(input));
> +	for (i = 110; i < sizeof(input); i++) {


Why 100 and not 50? ;)


> +		err |= test_hash(sha384, hash, 48, input, i, SHA384);
> +		err |= test_hash(sha512, hash, sizeof(hash), input, i, SHA512);
> +	}
> +
> +	return err;
> +}
> +#endif
> diff --git a/lib/libtpm/sha_test.h b/lib/libtpm/sha_test.h
> new file mode 100644
> index 0000000..e1358f9
> --- /dev/null
> +++ b/lib/libtpm/sha_test.h
> @@ -0,0 +1,58 @@
> +/*****************************************************************************
> + * Copyright (c) 2021 IBM Corporation
> + * All rights reserved.
> + * This program and the accompanying materials
> + * are made available under the terms of the BSD License
> + * which accompanies this distribution, and is available at
> + * http://www.opensource.org/licenses/bsd-license.php
> + *
> + * Contributors:
> + *     IBM Corporation - initial implementation
> + *****************************************************************************/
> +
> +#ifndef SHA_TEST_H
> +#define SHA_TEST_H
> +
> +#include <stdio.h>
> +
> +/* to avoid compilation issues do not include openssl/sha.h */
> +unsigned char *SHA1(const unsigned char *, size_t, unsigned char *);
> +unsigned char *SHA256(const unsigned char *, size_t, unsigned char *);
> +unsigned char *SHA384(const unsigned char *, size_t, unsigned char *);
> +unsigned char *SHA512(const unsigned char *, size_t, unsigned char *);
> +
> +typedef void (*hashfunc)(const uint8_t *data, uint32_t length, uint8_t *hash);
> +typedef unsigned char *(*osslhashfunc)(const unsigned char *, size_t,
> +				       unsigned char *);
> +
> +#define TESTVECTORS(NAME) \
> +char *NAME[] = {	\
> +	"",		\
> +	"abc",		\
> +	"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", \
> +	"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", \
> +	NULL		\


Use ARRAY_SIZE(NAME) and ditch this last NULL?


> +};
> +
> +static inline int
> +test_hash(hashfunc hf, uint8_t *hash, size_t hashlen,
> +	   const char *data, uint32_t length,
> +	   osslhashfunc osslhf)
> +{
> +	unsigned char expected[hashlen];
> +	int ret = 0;
> +
> +	osslhf((const unsigned char *)data, length, expected);
> +
> +	hf((uint8_t *)data, length, hash);
> +	if (!memcmp(hash, expected, hashlen)) {
> +		printf("PASS\n");
> +	} else {
> +		printf("FAIL data: %s\n", data);
> +		ret = 1;
> +	}
> +
> +	return ret;
> +}
> +
> +#endif /* SHA_TEST_H */
> diff --git a/lib/libtpm/test.sh b/lib/libtpm/test.sh
> new file mode 100755
> index 0000000..f375fbc
> --- /dev/null
> +++ b/lib/libtpm/test.sh
> @@ -0,0 +1,29 @@
> +#!/usr/bin/env bash
> +cd $(dirname "$0")
> +
> +function fail() {
> +	echo "Test failed"
> +	exit 1

If we end up here, the produced binaries are not removed.


> +}
> +
> +CC=${HOSTCC:-gcc}
> +CFLAGS="-Wall -Wextra -Werror -I../../include -I../../slof -I../../lib/libc/include -DMAIN"
> +LDFLAGS="-lcrypto"
> +
> +echo "SHA-1 test:"
> +${CC} ${CFLAGS} sha.c -o sha-test ${LDFLAGS} || exit 1


This produces a little endian binary (as these days PPC64 is pretty much 
always LE) but SLOF and libtpm are big endian and this is a potential 
source of bugs, the test must somehow take this into account imho. I am 
really not sure how to address this though :-/


> +./sha-test || fail
> +rm -f sha-test
> +
> +echo "SHA-256 test:"
> +${CC} ${CFLAGS} sha256.c -o sha256-test ${LDFLAGS} || exit 1
> +./sha256-test || fail
> +rm -f sha256-test
> +
> +echo "SHA-384 & 512 test:"
> +${CC} ${CFLAGS} sha512.c -o sha512-test ${LDFLAGS} || exit 1
> +./sha512-test || fail
> +rm -f sha512-test
> +
> +echo "All tests passed"
> +exit 0
>
Stefan Berger July 9, 2021, 12:07 p.m. UTC | #2
On 7/9/21 2:02 AM, Alexey Kardashevskiy wrote:

>
>
> On 09/07/2021 12:53, Stefan Berger wrote:
>> From: Stefan Berger <stefanb@linux.ibm.com>
>>
>> Add test cases for sha1, sha256, sha384, and sha512 and a test script
>> to run the test cases.
>>
>> Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
>> ---
>>   lib/libtpm/sha.c      | 26 +++++++++++++++++++
>>   lib/libtpm/sha256.c   | 25 +++++++++++++++++++
>>   lib/libtpm/sha512.c   | 32 ++++++++++++++++++++++++
>>   lib/libtpm/sha_test.h | 58 +++++++++++++++++++++++++++++++++++++++++++
>>   lib/libtpm/test.sh    | 29 ++++++++++++++++++++++
>>   5 files changed, 170 insertions(+)
>>   create mode 100644 lib/libtpm/sha_test.h
>>   create mode 100755 lib/libtpm/test.sh
>>
>> diff --git a/lib/libtpm/sha.c b/lib/libtpm/sha.c
>> index 43de658..6e8b19b 100644
>> --- a/lib/libtpm/sha.c
>> +++ b/lib/libtpm/sha.c
>> @@ -203,3 +203,29 @@ void sha1(const uint8_t *data, uint32_t length, 
>> uint8_t *hash)
>>       sha1_do(&ctx, data, length);
>>       memcpy(hash, &ctx.h[0], 20);
>>   }
>> +
>> +#ifdef MAIN
>> +
>> +#include "sha_test.h"
>> +
>> +int main(void)
>> +{
>> +    TESTVECTORS(data);
>> +    uint8_t hash[20];
>> +    char input[64];
>> +    int err = 0;
>> +    size_t i;
>> +
>> +    for (i = 0; data[i]; i++)
>> +        err |= test_hash(sha1, hash, sizeof(hash),
>> +                 data[i], strlen(data[i]),
>> +                 SHA1);
>> +
>> +    memset(input, 'a', sizeof(input));
>> +    for (i = 50; i < sizeof(input); i++)
>
>
> Why 50?


There's a critical point in the input size for sha1 at around 56 bytes. 
I mainly wanted to cover that.

https://github.com/aik/SLOF/blob/master/lib/libtpm/sha.c#L170

The same is true for sha256 at 56 bytes:

https://github.com/aik/SLOF/blob/master/lib/libtpm/sha256.c#L176

For sha512/sha384 it is at 112 bytes:

https://github.com/aik/SLOF/blob/master/lib/libtpm/sha512.c#L186


>
>
>> +        err |= test_hash(sha256, hash, sizeof(hash), input, i, SHA256);
>> +
>> +    return err;
>> +}
>> +#endif
>> diff --git a/lib/libtpm/sha512.c b/lib/libtpm/sha512.c
>> index f9267ef..9e856ea 100644
>> --- a/lib/libtpm/sha512.c
>> +++ b/lib/libtpm/sha512.c
>> @@ -247,3 +247,35 @@ void sha512(const uint8_t *data, uint32_t 
>> length, uint8_t *hash)
>>       sha512_do(&ctx, data, length);
>>       memcpy(hash, ctx.h, sizeof(ctx.h));
>>   }
>> +
>> +
>> +#ifdef MAIN
>> +
>> +#include "sha_test.h"
>> +
>> +int main(void)
>> +{
>> +    TESTVECTORS(data);
>> +    uint8_t hash[64];
>> +    char input[128];
>> +    int err = 0;
>> +    size_t i;
>> +
>> +    for (i = 0; data[i]; i++) {
>> +        err |= test_hash(sha384, hash, 48,
>
> Uff. Why 2 separate tests for 48 and sizeof(hash) here but everywhere 
> else it is just sizeof(hash)?

Ok, let me revise.


>
>
>
>> +                 data[i], strlen(data[i]),
>> +                 SHA384);
>> +        err |= test_hash(sha512, hash, sizeof(hash),
>> +                 data[i], strlen(data[i]),
>> +                 SHA512);
>> +    }
>> +
>> +    memset(input, 'a', sizeof(input));
>> +    for (i = 110; i < sizeof(input); i++) {
>
>
> Why 100 and not 50? ;)


See above.

>
>
>> +        err |= test_hash(sha384, hash, 48, input, i, SHA384);
>> +        err |= test_hash(sha512, hash, sizeof(hash), input, i, SHA512);
>> +    }
>> +
>> +    return err;
>> +}
>> +#endif
>> diff --git a/lib/libtpm/sha_test.h b/lib/libtpm/sha_test.h
>> new file mode 100644
>> index 0000000..e1358f9
>> --- /dev/null
>> +++ b/lib/libtpm/sha_test.h
>> @@ -0,0 +1,58 @@
>> +/***************************************************************************** 
>>
>> + * Copyright (c) 2021 IBM Corporation
>> + * All rights reserved.
>> + * This program and the accompanying materials
>> + * are made available under the terms of the BSD License
>> + * which accompanies this distribution, and is available at
>> + * http://www.opensource.org/licenses/bsd-license.php
>> + *
>> + * Contributors:
>> + *     IBM Corporation - initial implementation
>> + 
>> *****************************************************************************/
>> +
>> +#ifndef SHA_TEST_H
>> +#define SHA_TEST_H
>> +
>> +#include <stdio.h>
>> +
>> +/* to avoid compilation issues do not include openssl/sha.h */
>> +unsigned char *SHA1(const unsigned char *, size_t, unsigned char *);
>> +unsigned char *SHA256(const unsigned char *, size_t, unsigned char *);
>> +unsigned char *SHA384(const unsigned char *, size_t, unsigned char *);
>> +unsigned char *SHA512(const unsigned char *, size_t, unsigned char *);
>> +
>> +typedef void (*hashfunc)(const uint8_t *data, uint32_t length, 
>> uint8_t *hash);
>> +typedef unsigned char *(*osslhashfunc)(const unsigned char *, size_t,
>> +                       unsigned char *);
>> +
>> +#define TESTVECTORS(NAME) \
>> +char *NAME[] = {    \
>> +    "",        \
>> +    "abc",        \
>> +    "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", \
>> + 
>> "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 
>> \
>> +    NULL        \
>
>
> Use ARRAY_SIZE(NAME) and ditch this last NULL?


Ok.


>
>
>> +};
>> +
>> +static inline int
>> +test_hash(hashfunc hf, uint8_t *hash, size_t hashlen,
>> +       const char *data, uint32_t length,
>> +       osslhashfunc osslhf)
>> +{
>> +    unsigned char expected[hashlen];
>> +    int ret = 0;
>> +
>> +    osslhf((const unsigned char *)data, length, expected);
>> +
>> +    hf((uint8_t *)data, length, hash);
>> +    if (!memcmp(hash, expected, hashlen)) {
>> +        printf("PASS\n");
>> +    } else {
>> +        printf("FAIL data: %s\n", data);
>> +        ret = 1;
>> +    }
>> +
>> +    return ret;
>> +}
>> +
>> +#endif /* SHA_TEST_H */
>> diff --git a/lib/libtpm/test.sh b/lib/libtpm/test.sh
>> new file mode 100755
>> index 0000000..f375fbc
>> --- /dev/null
>> +++ b/lib/libtpm/test.sh
>> @@ -0,0 +1,29 @@
>> +#!/usr/bin/env bash
>> +cd $(dirname "$0")
>> +
>> +function fail() {
>> +    echo "Test failed"
>> +    exit 1
>
> If we end up here, the produced binaries are not removed.
>
>
>> +}
>> +
>> +CC=${HOSTCC:-gcc}
>> +CFLAGS="-Wall -Wextra -Werror -I../../include -I../../slof 
>> -I../../lib/libc/include -DMAIN"
>> +LDFLAGS="-lcrypto"
>> +
>> +echo "SHA-1 test:"
>> +${CC} ${CFLAGS} sha.c -o sha-test ${LDFLAGS} || exit 1
>
>
> This produces a little endian binary (as these days PPC64 is pretty 
> much always LE) but SLOF and libtpm are big endian and this is a 
> potential source of bugs, the test must somehow take this into account 
> imho. I am really not sure how to address this though :-/


I ran it on an old big endian Fedora 28. Well, it works there. The only 
other choice would be to add this as self-tests into SLOF and use 
hard-coded results for comparison.


>
>
>
>> +./sha-test || fail
>> +rm -f sha-test
>> +
>> +echo "SHA-256 test:"
>> +${CC} ${CFLAGS} sha256.c -o sha256-test ${LDFLAGS} || exit 1
>> +./sha256-test || fail
>> +rm -f sha256-test
>> +
>> +echo "SHA-384 & 512 test:"
>> +${CC} ${CFLAGS} sha512.c -o sha512-test ${LDFLAGS} || exit 1
>> +./sha512-test || fail
>> +rm -f sha512-test
>> +
>> +echo "All tests passed"
>> +exit 0
>>
>
Alexey Kardashevskiy July 9, 2021, 2:07 p.m. UTC | #3
On 09/07/2021 22:07, Stefan Berger wrote:
> On 7/9/21 2:02 AM, Alexey Kardashevskiy wrote:
> 
>>
>>
>> On 09/07/2021 12:53, Stefan Berger wrote:
>>> From: Stefan Berger <stefanb@linux.ibm.com>
>>>
>>> Add test cases for sha1, sha256, sha384, and sha512 and a test script
>>> to run the test cases.
>>>
>>> Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
>>> ---
>>>   lib/libtpm/sha.c      | 26 +++++++++++++++++++
>>>   lib/libtpm/sha256.c   | 25 +++++++++++++++++++
>>>   lib/libtpm/sha512.c   | 32 ++++++++++++++++++++++++
>>>   lib/libtpm/sha_test.h | 58 +++++++++++++++++++++++++++++++++++++++++++
>>>   lib/libtpm/test.sh    | 29 ++++++++++++++++++++++
>>>   5 files changed, 170 insertions(+)
>>>   create mode 100644 lib/libtpm/sha_test.h
>>>   create mode 100755 lib/libtpm/test.sh
>>>
>>> diff --git a/lib/libtpm/sha.c b/lib/libtpm/sha.c
>>> index 43de658..6e8b19b 100644
>>> --- a/lib/libtpm/sha.c
>>> +++ b/lib/libtpm/sha.c
>>> @@ -203,3 +203,29 @@ void sha1(const uint8_t *data, uint32_t length, 
>>> uint8_t *hash)
>>>       sha1_do(&ctx, data, length);
>>>       memcpy(hash, &ctx.h[0], 20);
>>>   }
>>> +
>>> +#ifdef MAIN
>>> +
>>> +#include "sha_test.h"
>>> +
>>> +int main(void)
>>> +{
>>> +    TESTVECTORS(data);
>>> +    uint8_t hash[20];
>>> +    char input[64];
>>> +    int err = 0;
>>> +    size_t i;
>>> +
>>> +    for (i = 0; data[i]; i++)
>>> +        err |= test_hash(sha1, hash, sizeof(hash),
>>> +                 data[i], strlen(data[i]),
>>> +                 SHA1);
>>> +
>>> +    memset(input, 'a', sizeof(input));
>>> +    for (i = 50; i < sizeof(input); i++)
>>
>>
>> Why 50?
> 
> 
> There's a critical point in the input size for sha1 at around 56 bytes. 
> I mainly wanted to cover that.

This is fine but then it calls for a macro, something like 
SHA1_CRIT_SIZE which you then use in sha.c and in the test. I never ever 
wrote a single bit of sha so I really wish to have some clues here.


> https://github.com/aik/SLOF/blob/master/lib/libtpm/sha.c#L170
> 
> The same is true for sha256 at 56 bytes:
> 
> https://github.com/aik/SLOF/blob/master/lib/libtpm/sha256.c#L176
> 
> For sha512/sha384 it is at 112 bytes:
>
> https://github.com/aik/SLOF/blob/master/lib/libtpm/sha512.c#L186
> 
> 
>>
>>
>>> +        err |= test_hash(sha256, hash, sizeof(hash), input, i, SHA256);
>>> +
>>> +    return err;
>>> +}
>>> +#endif
>>> diff --git a/lib/libtpm/sha512.c b/lib/libtpm/sha512.c
>>> index f9267ef..9e856ea 100644
>>> --- a/lib/libtpm/sha512.c
>>> +++ b/lib/libtpm/sha512.c
>>> @@ -247,3 +247,35 @@ void sha512(const uint8_t *data, uint32_t 
>>> length, uint8_t *hash)
>>>       sha512_do(&ctx, data, length);
>>>       memcpy(hash, ctx.h, sizeof(ctx.h));
>>>   }
>>> +
>>> +
>>> +#ifdef MAIN
>>> +
>>> +#include "sha_test.h"
>>> +
>>> +int main(void)
>>> +{
>>> +    TESTVECTORS(data);
>>> +    uint8_t hash[64];
>>> +    char input[128];
>>> +    int err = 0;
>>> +    size_t i;
>>> +
>>> +    for (i = 0; data[i]; i++) {
>>> +        err |= test_hash(sha384, hash, 48,
>>
>> Uff. Why 2 separate tests for 48 and sizeof(hash) here but everywhere 
>> else it is just sizeof(hash)?
> 
> Ok, let me revise.
> 
> 
>>
>>
>>
>>> +                 data[i], strlen(data[i]),
>>> +                 SHA384);
>>> +        err |= test_hash(sha512, hash, sizeof(hash),
>>> +                 data[i], strlen(data[i]),
>>> +                 SHA512);
>>> +    }
>>> +
>>> +    memset(input, 'a', sizeof(input));
>>> +    for (i = 110; i < sizeof(input); i++) {
>>
>>
>> Why 100 and not 50? ;)
> 
> 
> See above.
> 
>>
>>
>>> +        err |= test_hash(sha384, hash, 48, input, i, SHA384);
>>> +        err |= test_hash(sha512, hash, sizeof(hash), input, i, SHA512);
>>> +    }
>>> +
>>> +    return err;
>>> +}
>>> +#endif
>>> diff --git a/lib/libtpm/sha_test.h b/lib/libtpm/sha_test.h
>>> new file mode 100644
>>> index 0000000..e1358f9
>>> --- /dev/null
>>> +++ b/lib/libtpm/sha_test.h
>>> @@ -0,0 +1,58 @@
>>> +/***************************************************************************** 
>>>
>>> + * Copyright (c) 2021 IBM Corporation
>>> + * All rights reserved.
>>> + * This program and the accompanying materials
>>> + * are made available under the terms of the BSD License
>>> + * which accompanies this distribution, and is available at
>>> + * http://www.opensource.org/licenses/bsd-license.php
>>> + *
>>> + * Contributors:
>>> + *     IBM Corporation - initial implementation
>>> + 
>>> *****************************************************************************/ 
>>>
>>> +
>>> +#ifndef SHA_TEST_H
>>> +#define SHA_TEST_H
>>> +
>>> +#include <stdio.h>
>>> +
>>> +/* to avoid compilation issues do not include openssl/sha.h */
>>> +unsigned char *SHA1(const unsigned char *, size_t, unsigned char *);
>>> +unsigned char *SHA256(const unsigned char *, size_t, unsigned char *);
>>> +unsigned char *SHA384(const unsigned char *, size_t, unsigned char *);
>>> +unsigned char *SHA512(const unsigned char *, size_t, unsigned char *);
>>> +
>>> +typedef void (*hashfunc)(const uint8_t *data, uint32_t length, 
>>> uint8_t *hash);
>>> +typedef unsigned char *(*osslhashfunc)(const unsigned char *, size_t,
>>> +                       unsigned char *);
>>> +
>>> +#define TESTVECTORS(NAME) \
>>> +char *NAME[] = {    \
>>> +    "",        \
>>> +    "abc",        \
>>> +    "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", \
>>> + 
>>> "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 
>>> \
>>> +    NULL        \
>>
>>
>> Use ARRAY_SIZE(NAME) and ditch this last NULL?
> 
> 
> Ok.
> 
> 
>>
>>
>>> +};
>>> +
>>> +static inline int
>>> +test_hash(hashfunc hf, uint8_t *hash, size_t hashlen,
>>> +       const char *data, uint32_t length,
>>> +       osslhashfunc osslhf)
>>> +{
>>> +    unsigned char expected[hashlen];
>>> +    int ret = 0;
>>> +
>>> +    osslhf((const unsigned char *)data, length, expected);
>>> +
>>> +    hf((uint8_t *)data, length, hash);
>>> +    if (!memcmp(hash, expected, hashlen)) {
>>> +        printf("PASS\n");
>>> +    } else {
>>> +        printf("FAIL data: %s\n", data);
>>> +        ret = 1;
>>> +    }
>>> +
>>> +    return ret;
>>> +}
>>> +
>>> +#endif /* SHA_TEST_H */
>>> diff --git a/lib/libtpm/test.sh b/lib/libtpm/test.sh
>>> new file mode 100755
>>> index 0000000..f375fbc
>>> --- /dev/null
>>> +++ b/lib/libtpm/test.sh
>>> @@ -0,0 +1,29 @@
>>> +#!/usr/bin/env bash
>>> +cd $(dirname "$0")
>>> +
>>> +function fail() {
>>> +    echo "Test failed"
>>> +    exit 1
>>
>> If we end up here, the produced binaries are not removed.
>>
>>
>>> +}
>>> +
>>> +CC=${HOSTCC:-gcc}
>>> +CFLAGS="-Wall -Wextra -Werror -I../../include -I../../slof 
>>> -I../../lib/libc/include -DMAIN"
>>> +LDFLAGS="-lcrypto"
>>> +
>>> +echo "SHA-1 test:"
>>> +${CC} ${CFLAGS} sha.c -o sha-test ${LDFLAGS} || exit 1
>>
>>
>> This produces a little endian binary (as these days PPC64 is pretty 
>> much always LE) but SLOF and libtpm are big endian and this is a 
>> potential source of bugs, the test must somehow take this into account 
>> imho. I am really not sure how to address this though :-/
> 
> 
> I ran it on an old big endian Fedora 28. Well, it works there.

ok, this will do, may be leave a note in the commit log. Thanks,


> The only 
> other choice would be to add this as self-tests into SLOF and use 
> hard-coded results for comparison.
> 
> 
>>
>>
>>
>>> +./sha-test || fail
>>> +rm -f sha-test
>>> +
>>> +echo "SHA-256 test:"
>>> +${CC} ${CFLAGS} sha256.c -o sha256-test ${LDFLAGS} || exit 1
>>> +./sha256-test || fail
>>> +rm -f sha256-test
>>> +
>>> +echo "SHA-384 & 512 test:"
>>> +${CC} ${CFLAGS} sha512.c -o sha512-test ${LDFLAGS} || exit 1
>>> +./sha512-test || fail
>>> +rm -f sha512-test
>>> +
>>> +echo "All tests passed"
>>> +exit 0
>>>
>>
Stefan Berger July 9, 2021, 2:46 p.m. UTC | #4
On 7/9/21 10:07 AM, Alexey Kardashevskiy wrote:
>
>
> On 09/07/2021 22:07, Stefan Berger wrote:
>> On 7/9/21 2:02 AM, Alexey Kardashevskiy wrote:
>>
>>>
>>>
>>> On 09/07/2021 12:53, Stefan Berger wrote:
>>>> From: Stefan Berger <stefanb@linux.ibm.com>
>>>>
>>>> Add test cases for sha1, sha256, sha384, and sha512 and a test script
>>>> to run the test cases.
>>>>
>>>> Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
>>>> ---
>>>>   lib/libtpm/sha.c      | 26 +++++++++++++++++++
>>>>   lib/libtpm/sha256.c   | 25 +++++++++++++++++++
>>>>   lib/libtpm/sha512.c   | 32 ++++++++++++++++++++++++
>>>>   lib/libtpm/sha_test.h | 58 
>>>> +++++++++++++++++++++++++++++++++++++++++++
>>>>   lib/libtpm/test.sh    | 29 ++++++++++++++++++++++
>>>>   5 files changed, 170 insertions(+)
>>>>   create mode 100644 lib/libtpm/sha_test.h
>>>>   create mode 100755 lib/libtpm/test.sh
>>>>
>>>> diff --git a/lib/libtpm/sha.c b/lib/libtpm/sha.c
>>>> index 43de658..6e8b19b 100644
>>>> --- a/lib/libtpm/sha.c
>>>> +++ b/lib/libtpm/sha.c
>>>> @@ -203,3 +203,29 @@ void sha1(const uint8_t *data, uint32_t 
>>>> length, uint8_t *hash)
>>>>       sha1_do(&ctx, data, length);
>>>>       memcpy(hash, &ctx.h[0], 20);
>>>>   }
>>>> +
>>>> +#ifdef MAIN
>>>> +
>>>> +#include "sha_test.h"
>>>> +
>>>> +int main(void)
>>>> +{
>>>> +    TESTVECTORS(data);
>>>> +    uint8_t hash[20];
>>>> +    char input[64];
>>>> +    int err = 0;
>>>> +    size_t i;
>>>> +
>>>> +    for (i = 0; data[i]; i++)
>>>> +        err |= test_hash(sha1, hash, sizeof(hash),
>>>> +                 data[i], strlen(data[i]),
>>>> +                 SHA1);
>>>> +
>>>> +    memset(input, 'a', sizeof(input));
>>>> +    for (i = 50; i < sizeof(input); i++)
>>>
>>>
>>> Why 50?
>>
>>
>> There's a critical point in the input size for sha1 at around 56 
>> bytes. I mainly wanted to cover that.
>
> This is fine but then it calls for a macro, something like 
> SHA1_CRIT_SIZE which you then use in sha.c and in the test. I never 
> ever wrote a single bit of sha so I really wish to have some clues here.


I now wrote a comment into the code explaining what the critical input 
size is and that we want to cover that along with some more tests around 
that size...
diff mbox series

Patch

diff --git a/lib/libtpm/sha.c b/lib/libtpm/sha.c
index 43de658..6e8b19b 100644
--- a/lib/libtpm/sha.c
+++ b/lib/libtpm/sha.c
@@ -203,3 +203,29 @@  void sha1(const uint8_t *data, uint32_t length, uint8_t *hash)
 	sha1_do(&ctx, data, length);
 	memcpy(hash, &ctx.h[0], 20);
 }
+
+#ifdef MAIN
+
+#include "sha_test.h"
+
+int main(void)
+{
+	TESTVECTORS(data);
+	uint8_t hash[20];
+	char input[64];
+	int err = 0;
+	size_t i;
+
+	for (i = 0; data[i]; i++)
+		err |= test_hash(sha1, hash, sizeof(hash),
+				 data[i], strlen(data[i]),
+				 SHA1);
+
+	memset(input, 'a', sizeof(input));
+	for (i = 50; i < sizeof(input); i++)
+		err |= test_hash(sha1, hash, sizeof(hash),
+				 input, i, SHA1);
+
+	return err;
+}
+#endif
diff --git a/lib/libtpm/sha256.c b/lib/libtpm/sha256.c
index 1a0aa9a..c921ff5 100644
--- a/lib/libtpm/sha256.c
+++ b/lib/libtpm/sha256.c
@@ -218,3 +218,28 @@  void sha256(const uint8_t *data, uint32_t length, uint8_t *hash)
 	sha256_do(&ctx, data, length);
 	memcpy(hash, ctx.h, sizeof(ctx.h));
 }
+
+#ifdef MAIN
+
+#include "sha_test.h"
+
+int main(void)
+{
+	TESTVECTORS(data);
+	uint8_t hash[32];
+	char input[64];
+	int err = 0;
+	size_t i;
+
+	for (i = 0; data[i]; i++)
+		err |= test_hash(sha256, hash, sizeof(hash),
+				 data[i], strlen(data[i]),
+				 SHA256);
+
+	memset(input, 'a', sizeof(input));
+	for (i = 50; i < sizeof(input); i++)
+		err |= test_hash(sha256, hash, sizeof(hash), input, i, SHA256);
+
+	return err;
+}
+#endif
diff --git a/lib/libtpm/sha512.c b/lib/libtpm/sha512.c
index f9267ef..9e856ea 100644
--- a/lib/libtpm/sha512.c
+++ b/lib/libtpm/sha512.c
@@ -247,3 +247,35 @@  void sha512(const uint8_t *data, uint32_t length, uint8_t *hash)
 	sha512_do(&ctx, data, length);
 	memcpy(hash, ctx.h, sizeof(ctx.h));
 }
+
+
+#ifdef MAIN
+
+#include "sha_test.h"
+
+int main(void)
+{
+	TESTVECTORS(data);
+	uint8_t hash[64];
+	char input[128];
+	int err = 0;
+	size_t i;
+
+	for (i = 0; data[i]; i++) {
+		err |= test_hash(sha384, hash, 48,
+				 data[i], strlen(data[i]),
+				 SHA384);
+		err |= test_hash(sha512, hash, sizeof(hash),
+				 data[i], strlen(data[i]),
+				 SHA512);
+	}
+
+	memset(input, 'a', sizeof(input));
+	for (i = 110; i < sizeof(input); i++) {
+		err |= test_hash(sha384, hash, 48, input, i, SHA384);
+		err |= test_hash(sha512, hash, sizeof(hash), input, i, SHA512);
+	}
+
+	return err;
+}
+#endif
diff --git a/lib/libtpm/sha_test.h b/lib/libtpm/sha_test.h
new file mode 100644
index 0000000..e1358f9
--- /dev/null
+++ b/lib/libtpm/sha_test.h
@@ -0,0 +1,58 @@ 
+/*****************************************************************************
+ * Copyright (c) 2021 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef SHA_TEST_H
+#define SHA_TEST_H
+
+#include <stdio.h>
+
+/* to avoid compilation issues do not include openssl/sha.h */
+unsigned char *SHA1(const unsigned char *, size_t, unsigned char *);
+unsigned char *SHA256(const unsigned char *, size_t, unsigned char *);
+unsigned char *SHA384(const unsigned char *, size_t, unsigned char *);
+unsigned char *SHA512(const unsigned char *, size_t, unsigned char *);
+
+typedef void (*hashfunc)(const uint8_t *data, uint32_t length, uint8_t *hash);
+typedef unsigned char *(*osslhashfunc)(const unsigned char *, size_t,
+				       unsigned char *);
+
+#define TESTVECTORS(NAME) \
+char *NAME[] = {	\
+	"",		\
+	"abc",		\
+	"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", \
+	"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", \
+	NULL		\
+};
+
+static inline int
+test_hash(hashfunc hf, uint8_t *hash, size_t hashlen,
+	   const char *data, uint32_t length,
+	   osslhashfunc osslhf)
+{
+	unsigned char expected[hashlen];
+	int ret = 0;
+
+	osslhf((const unsigned char *)data, length, expected);
+
+	hf((uint8_t *)data, length, hash);
+	if (!memcmp(hash, expected, hashlen)) {
+		printf("PASS\n");
+	} else {
+		printf("FAIL data: %s\n", data);
+		ret = 1;
+	}
+
+	return ret;
+}
+
+#endif /* SHA_TEST_H */
diff --git a/lib/libtpm/test.sh b/lib/libtpm/test.sh
new file mode 100755
index 0000000..f375fbc
--- /dev/null
+++ b/lib/libtpm/test.sh
@@ -0,0 +1,29 @@ 
+#!/usr/bin/env bash
+cd $(dirname "$0")
+
+function fail() {
+	echo "Test failed"
+	exit 1
+}
+
+CC=${HOSTCC:-gcc}
+CFLAGS="-Wall -Wextra -Werror -I../../include -I../../slof -I../../lib/libc/include -DMAIN"
+LDFLAGS="-lcrypto"
+
+echo "SHA-1 test:"
+${CC} ${CFLAGS} sha.c -o sha-test ${LDFLAGS} || exit 1
+./sha-test || fail
+rm -f sha-test
+
+echo "SHA-256 test:"
+${CC} ${CFLAGS} sha256.c -o sha256-test ${LDFLAGS} || exit 1
+./sha256-test || fail
+rm -f sha256-test
+
+echo "SHA-384 & 512 test:"
+${CC} ${CFLAGS} sha512.c -o sha512-test ${LDFLAGS} || exit 1
+./sha512-test || fail
+rm -f sha512-test
+
+echo "All tests passed"
+exit 0