blob: 2228c26eb0818f1095ca7fee0a684c20f6ce389c [file] [log] [blame]
/* Microsoft Reference Implementation for TPM 2.0
*
* The copyright in this software is being made available under the BSD License,
* included below. This software may be subject to other third party and
* contributor rights, including patent rights, and no such rights are granted
* under this license.
*
* Copyright (c) Microsoft Corporation
*
* All rights reserved.
*
* BSD License
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//** Introduction
// This file contains the code to perform the various self-test functions.
//** Includes and Defines
#include "Tpm.h"
#define SELF_TEST_DATA
#ifdef SELF_TEST
// These includes pull in the data structures. They contain data definitions for the
// various tests.
#include "SelfTest.h"
#include "SymmetricTest.h"
#include "RsaTestData.h"
#include "EccTestData.h"
#include "HashTestData.h"
#define TEST_DEFAULT_TEST_HASH(vector) \
if(TEST_BIT(DEFAULT_TEST_HASH, g_toTest)) \
TestHash(DEFAULT_TEST_HASH, vector);
// Make sure that the algorithm has been tested
#define CLEAR_BOTH(alg) { CLEAR_BIT(alg, *toTest); \
if(toTest != &g_toTest) \
CLEAR_BIT(alg, g_toTest); }
#define SET_BOTH(alg) { SET_BIT(alg, *toTest); \
if(toTest != &g_toTest) \
SET_BIT(alg, g_toTest); }
#define TEST_BOTH(alg) ((toTest != &g_toTest) \
? TEST_BIT(alg, *toTest) || TEST_BIT(alg, g_toTest) \
: TEST_BIT(alg, *toTest))
// Can only cancel if doing a list.
#define CHECK_CANCELED \
if(_plat__IsCanceled() && toTest != &g_toTest) \
return TPM_RC_CANCELED;
//** Hash Tests
//*** Description
// The hash test does a known-value HMAC using the specified hash algorithm.
//*** TestHash()
// The hash test function.
static TPM_RC
TestHash(
TPM_ALG_ID hashAlg,
ALGORITHM_VECTOR *toTest
)
{
TPM2B_DIGEST computed; // value computed
UINT16 digestSize;
const TPM2B *testDigest = NULL;
HMAC_STATE state;
// TPM2B_TYPE(HMAC_BLOCK, DEFAULT_TEST_HASH_BLOCK_SIZE);
pAssert(hashAlg != TPM_ALG_NULL);
switch(hashAlg)
{
#if ALG_SHA1
case ALG_SHA1_VALUE:
testDigest = &c_SHA1_digest.b;
break;
#endif
#if ALG_SHA256
case ALG_SHA256_VALUE:
testDigest = &c_SHA256_digest.b;
break;
#endif
#if ALG_SHA384
case ALG_SHA384_VALUE:
testDigest = &c_SHA384_digest.b;
break;
#endif
#if ALG_SHA512
case ALG_SHA512_VALUE:
testDigest = &c_SHA512_digest.b;
break;
#endif
#if ALG_SM3_256
case ALG_SM3_256_VALUE:
testDigest = &c_SM3_256_digest.b;
break;
#endif
default:
FAIL(FATAL_ERROR_INTERNAL);
}
// Clear the to-test bits
CLEAR_BOTH(hashAlg);
// Set the HMAC key to twice the digest size
digestSize = CryptHashGetDigestSize(hashAlg);
CryptHmacStart(&state, hashAlg, digestSize * 2,
(BYTE *)c_hashTestKey.t.buffer);
CryptDigestUpdate(&state.hashState, 2 * CryptHashGetBlockSize(hashAlg),
(BYTE *)c_hashTestData.t.buffer);
computed.t.size = digestSize;
CryptHmacEnd(&state, digestSize, computed.t.buffer);
if((testDigest->size != computed.t.size)
|| (memcmp(testDigest->buffer, computed.t.buffer, computed.b.size) != 0))
SELF_TEST_FAILURE;
return TPM_RC_SUCCESS;
}
//** Symmetric Test Functions
//*** MakeIv()
// Internal function to make the appropriate IV depending on the mode.
static UINT32
MakeIv(
TPM_ALG_ID mode, // IN: symmetric mode
UINT32 size, // IN: block size of the algorithm
BYTE *iv // OUT: IV to fill in
)
{
BYTE i;
if(mode == ALG_ECB_VALUE)
return 0;
if(mode == ALG_CTR_VALUE)
{
// The test uses an IV that has 0xff in the last byte
for(i = 1; i <= size; i++)
*iv++ = 0xff - (BYTE)(size - i);
}
else
{
for(i = 0; i < size; i++)
*iv++ = i;
}
return size;
}
//*** TestSymmetricAlgorithm()
// Function to test a specific algorithm, key size, and mode.
static void
TestSymmetricAlgorithm(
const SYMMETRIC_TEST_VECTOR *test, //
TPM_ALG_ID mode //
)
{
BYTE encrypted[MAX_SYM_BLOCK_SIZE * 2];
BYTE decrypted[MAX_SYM_BLOCK_SIZE * 2];
TPM2B_IV iv;
//
// Get the appropriate IV
iv.t.size = (UINT16)MakeIv(mode, test->ivSize, iv.t.buffer);
// Encrypt known data
CryptSymmetricEncrypt(encrypted, test->alg, test->keyBits, test->key, &iv,
mode, test->dataInOutSize, test->dataIn);
// Check that it matches the expected value
if(!MemoryEqual(encrypted, test->dataOut[mode - ALG_CTR_VALUE],
test->dataInOutSize))
SELF_TEST_FAILURE;
// Reinitialize the iv for decryption
MakeIv(mode, test->ivSize, iv.t.buffer);
CryptSymmetricDecrypt(decrypted, test->alg, test->keyBits, test->key, &iv,
mode, test->dataInOutSize,
test->dataOut[mode - ALG_CTR_VALUE]);
// Make sure that it matches what we started with
if(!MemoryEqual(decrypted, test->dataIn, test->dataInOutSize))
SELF_TEST_FAILURE;
}
//*** AllSymsAreDone()
// Checks if both symmetric algorithms have been tested. This is put here
// so that addition of a symmetric algorithm will be relatively easy to handle
static BOOL
AllSymsAreDone(
ALGORITHM_VECTOR *toTest
)
{
return (!TEST_BOTH(ALG_AES_VALUE) && !TEST_BOTH(ALG_SM4_VALUE));
}
//*** AllModesAreDone()
// Checks if all the modes have been tested
static BOOL
AllModesAreDone(
ALGORITHM_VECTOR *toTest
)
{
TPM_ALG_ID alg;
for(alg = TPM_SYM_MODE_FIRST; alg <= TPM_SYM_MODE_LAST; alg++)
if(TEST_BOTH(alg))
return FALSE;
return TRUE;
}
//*** TestSymmetric()
// If 'alg' is a symmetric block cipher, then all of the modes that are selected are
// tested. If 'alg' is a mode, then all algorithms of that mode are tested.
static TPM_RC
TestSymmetric(
TPM_ALG_ID alg,
ALGORITHM_VECTOR *toTest
)
{
SYM_INDEX index;
TPM_ALG_ID mode;
//
if(!TEST_BIT(alg, *toTest))
return TPM_RC_SUCCESS;
if(alg == ALG_AES_VALUE || alg == ALG_SM4_VALUE || alg == ALG_CAMELLIA_VALUE)
{
// Will test the algorithm for all modes and key sizes
CLEAR_BOTH(alg);
// A test this algorithm for all modes
for(index = 0; index < NUM_SYMS; index++)
{
if(c_symTestValues[index].alg == alg)
{
for(mode = TPM_SYM_MODE_FIRST;
mode <= TPM_SYM_MODE_LAST;
mode++)
{
if(TEST_BIT(mode, *toTest))
TestSymmetricAlgorithm(&c_symTestValues[index], mode);
}
}
}
// if all the symmetric tests are done
if(AllSymsAreDone(toTest))
{
// all symmetric algorithms tested so no modes should be set
for(alg = TPM_SYM_MODE_FIRST; alg <= TPM_SYM_MODE_LAST; alg++)
CLEAR_BOTH(alg);
}
}
else if(TPM_SYM_MODE_FIRST <= alg && alg <= TPM_SYM_MODE_LAST)
{
// Test this mode for all key sizes and algorithms
for(index = 0; index < NUM_SYMS; index++)
{
// The mode testing only comes into play when doing self tests
// by command. When doing self tests by command, the block ciphers are
// tested first. That means that all of their modes would have been
// tested for all key sizes. If there is no block cipher left to
// test, then clear this mode bit.
if(!TEST_BIT(ALG_AES_VALUE, *toTest)
&& !TEST_BIT(ALG_SM4_VALUE, *toTest))
{
CLEAR_BOTH(alg);
}
else
{
for(index = 0; index < NUM_SYMS; index++)
{
if(TEST_BIT(c_symTestValues[index].alg, *toTest))
TestSymmetricAlgorithm(&c_symTestValues[index], alg);
}
// have tested this mode for all algorithms
CLEAR_BOTH(alg);
}
}
if(AllModesAreDone(toTest))
{
CLEAR_BOTH(ALG_AES_VALUE);
CLEAR_BOTH(ALG_SM4_VALUE);
}
}
else
pAssert(alg == 0 && alg != 0);
return TPM_RC_SUCCESS;
}
//** RSA Tests
#ifdef TPM_ALG_RSA
//*** Introduction
// The tests are for public key only operations and for private key operations.
// Signature verification and encryption are public key operations. They are tested
// by using a KVT. For signature verification, this means that a known good
// signature is checked by CryptRsaValidateSignature(). If it fails, then the
// TPM enters failure mode. For encryption, the TPM encrypts known values using
// the selected scheme and checks that the returned value matches the expected
// value.
//
// For private key operations, a full scheme check is used. For a signing key, a
// known key is used to sign a known message. Then that signature is verified.
// since the signature may involve use of random values, the signature will be
// different each time and we can't always check that the signature matches a
// known value. The same technique is used for decryption (RSADP/RSAEP).
//
// When an operation uses the public key and the verification has not been
// tested, the TPM will do a KVT.
//
// The test for the signing algorithm is built into the call for the algorithm
//*** RsaKeyInitialize()
// The test key is defined by a public modulus and a private prime. The TPM's RSA
// code computes the second prime and the private exponent.
static void
RsaKeyInitialize(
OBJECT *testObject
)
{
MemoryCopy2B(&testObject->publicArea.unique.rsa.b, (P2B)&c_rsaPublicModulus,
sizeof(c_rsaPublicModulus));
MemoryCopy2B(&testObject->sensitive.sensitive.rsa.b, (P2B)&c_rsaPrivatePrime,
sizeof(testObject->sensitive.sensitive.rsa.t.buffer));
testObject->publicArea.parameters.rsaDetail.keyBits = RSA_TEST_KEY_SIZE * 8;
// Use the default exponent
testObject->publicArea.parameters.rsaDetail.exponent = 0;
testObject->attributes.privateExp = 0;
}
//*** TestRsaEncryptDecrypt()
// These test are for an public key encryption that uses a random value
static TPM_RC
TestRsaEncryptDecrypt(
TPM_ALG_ID scheme, // IN: the scheme
ALGORITHM_VECTOR *toTest //
)
{
TPM2B_PUBLIC_KEY_RSA testInput;
TPM2B_PUBLIC_KEY_RSA testOutput;
const TPM2B_RSA_TEST_KEY *kvtValue = &c_RsaesKvt;
TPM_RC result = TPM_RC_SUCCESS;
const TPM2B *testLabel = NULL;
OBJECT testObject;
TPMT_RSA_DECRYPT rsaScheme;
//
// Don't need to initialize much of the test object but do need to initialize
// the flag indicating that the private exponent has been computed.
testObject.attributes.privateExp = CLEAR;
RsaKeyInitialize(&testObject);
rsaScheme.scheme = scheme;
rsaScheme.details.anySig.hashAlg = DEFAULT_TEST_HASH;
CLEAR_BOTH(scheme);
CLEAR_BOTH(ALG_NULL_VALUE);
if(scheme == TPM_ALG_NULL)
{
// This is an encryption scheme using the private key without any encoding.
memcpy(testInput.t.buffer, c_RsaTestValue, sizeof(c_RsaTestValue));
testInput.t.size = sizeof(c_RsaTestValue);
if(TPM_RC_SUCCESS != CryptRsaEncrypt(&testOutput, &testInput.b,
&testObject, &rsaScheme, NULL, NULL))
SELF_TEST_FAILURE;
if(!MemoryEqual(testOutput.t.buffer, c_RsaepKvt.buffer, c_RsaepKvt.size))
SELF_TEST_FAILURE;
MemoryCopy2B(&testInput.b, &testOutput.b, sizeof(testInput.t.buffer));
if(TPM_RC_SUCCESS != CryptRsaDecrypt(&testOutput.b, &testInput.b,
&testObject, &rsaScheme, NULL))
SELF_TEST_FAILURE;
if(!MemoryEqual(testOutput.t.buffer, c_RsaTestValue,
sizeof(c_RsaTestValue)))
SELF_TEST_FAILURE;
}
else
{
// ALG_RSAES_VALUE:
// This is an decryption scheme using padding according to
// PKCS#1v2.1, 7.2. This padding uses random bits. To test a public
// key encryption that uses random data, encrypt a value and then
// decrypt the value and see that we get the encrypted data back.
// The hash is not used by this encryption so it can be TMP_ALG_NULL
// ALG_OAEP_VALUE:
// This is also an decryption scheme and it also uses a
// pseudo-random
// value. However, this also uses a hash algorithm. So, we may need
// to test that algorithm before use.
if(scheme == ALG_OAEP_VALUE)
{
TEST_DEFAULT_TEST_HASH(toTest);
kvtValue = &c_OaepKvt;
testLabel = OAEP_TEST_STRING;
}
else if(scheme == ALG_RSAES_VALUE)
{
kvtValue = &c_RsaesKvt;
testLabel = NULL;
}
else
SELF_TEST_FAILURE;
// Only use a digest-size portion of the test value
memcpy(testInput.t.buffer, c_RsaTestValue, DEFAULT_TEST_DIGEST_SIZE);
testInput.t.size = DEFAULT_TEST_DIGEST_SIZE;
// See if the encryption works
if(TPM_RC_SUCCESS != CryptRsaEncrypt(&testOutput, &testInput.b,
&testObject, &rsaScheme, testLabel,
NULL))
SELF_TEST_FAILURE;
MemoryCopy2B(&testInput.b, &testOutput.b, sizeof(testInput.t.buffer));
// see if we can decrypt this value and get the original data back
if(TPM_RC_SUCCESS != CryptRsaDecrypt(&testOutput.b, &testInput.b,
&testObject, &rsaScheme, testLabel))
SELF_TEST_FAILURE;
// See if the results compare
if(testOutput.t.size != DEFAULT_TEST_DIGEST_SIZE
|| !MemoryEqual(testOutput.t.buffer, c_RsaTestValue,
DEFAULT_TEST_DIGEST_SIZE))
SELF_TEST_FAILURE;
// Now check that the decryption works on a known value
MemoryCopy2B(&testInput.b, (P2B)kvtValue,
sizeof(testInput.t.buffer));
if(TPM_RC_SUCCESS != CryptRsaDecrypt(&testOutput.b, &testInput.b,
&testObject, &rsaScheme, testLabel))
SELF_TEST_FAILURE;
if(testOutput.t.size != DEFAULT_TEST_DIGEST_SIZE
|| !MemoryEqual(testOutput.t.buffer, c_RsaTestValue,
DEFAULT_TEST_DIGEST_SIZE))
SELF_TEST_FAILURE;
}
return result;
}
//*** TestRsaSignAndVerify()
// This function does the testing of the RSA sign and verification functions. This
// test does a KVT.
static TPM_RC
TestRsaSignAndVerify(
TPM_ALG_ID scheme,
ALGORITHM_VECTOR *toTest
)
{
TPM_RC result = TPM_RC_SUCCESS;
OBJECT testObject;
TPM2B_DIGEST testDigest;
TPMT_SIGNATURE testSig;
// Do a sign and signature verification.
// RSASSA:
// This is a signing scheme according to PKCS#1-v2.1 8.2. It does not
// use random data so there is a KVT for the signing operation. On
// first use of the scheme for signing, use the TPM's RSA key to
// sign a portion of c_RsaTestData and compare the results to c_RsassaKvt. Then
// decrypt the data to see that it matches the starting value. This verifies
// the signature with a KVT
// Clear the bits indicating that the function has not been checked. This is to
// prevent looping
CLEAR_BOTH(scheme);
CLEAR_BOTH(ALG_NULL_VALUE);
CLEAR_BOTH(ALG_RSA_VALUE);
RsaKeyInitialize(&testObject);
memcpy(testDigest.t.buffer, (BYTE *)c_RsaTestValue, DEFAULT_TEST_DIGEST_SIZE);
testDigest.t.size = DEFAULT_TEST_DIGEST_SIZE;
testSig.sigAlg = scheme;
testSig.signature.rsapss.hash = DEFAULT_TEST_HASH;
// RSAPSS:
// This is a signing scheme a according to PKCS#1-v2.2 8.1 it uses
// random data in the signature so there is no KVT for the signing
// operation. To test signing, the TPM will use the TPM's RSA key
// to sign a portion of c_RsaTestValue and then it will verify the
// signature. For verification, c_RsapssKvt is verified before the
// user signature blob is verified. The worst case for testing of this
// algorithm is two private and one public key operation.
// The process is to sign known data. If RSASSA is being done, verify that the
// signature matches the precomputed value. For both, use the signed value and
// see that the verification says that it is a good signature. Then
// if testing RSAPSS, do a verify of a known good signature. This ensures that
// the validation function works.
if(TPM_RC_SUCCESS != CryptRsaSign(&testSig, &testObject, &testDigest, NULL))
SELF_TEST_FAILURE;
// For RSASSA, make sure the results is what we are looking for
if(testSig.sigAlg == ALG_RSASSA_VALUE)
{
if(testSig.signature.rsassa.sig.t.size != RSA_TEST_KEY_SIZE
|| !MemoryEqual(c_RsassaKvt.buffer,
testSig.signature.rsassa.sig.t.buffer,
RSA_TEST_KEY_SIZE))
SELF_TEST_FAILURE;
}
// See if the TPM will validate its own signatures
if(TPM_RC_SUCCESS != CryptRsaValidateSignature(&testSig, &testObject,
&testDigest))
SELF_TEST_FAILURE;
// If this is RSAPSS, check the verification with known signature
// Have to copy because CrytpRsaValidateSignature() eats the signature
if(ALG_RSAPSS_VALUE == scheme)
{
MemoryCopy2B(&testSig.signature.rsapss.sig.b, (P2B)&c_RsapssKvt,
sizeof(testSig.signature.rsapss.sig.t.buffer));
if(TPM_RC_SUCCESS != CryptRsaValidateSignature(&testSig, &testObject,
&testDigest))
SELF_TEST_FAILURE;
}
return result;
}
//*** TestRSA()
// Function uses the provided vector to indicate which tests to run. It will clear
// the vector after each test is run and also clear g_toTest
static TPM_RC
TestRsa(
TPM_ALG_ID alg,
ALGORITHM_VECTOR *toTest
)
{
TPM_RC result = TPM_RC_SUCCESS;
//
switch(alg)
{
case ALG_NULL_VALUE:
// This is the RSAEP/RSADP function. If we are processing a list, don't
// need to test these now because any other test will validate
// RSAEP/RSADP. Can tell this is list of test by checking to see if
// 'toTest' is pointing at g_toTest. If so, this is an isolated test
// an need to go ahead and do the test;
if((toTest == &g_toTest)
|| (!TEST_BIT(ALG_RSASSA_VALUE, *toTest)
&& !TEST_BIT(ALG_RSAES_VALUE, *toTest)
&& !TEST_BIT(ALG_RSAPSS_VALUE, *toTest)
&& !TEST_BIT(ALG_OAEP_VALUE, *toTest)))
// Not running a list of tests or no other tests on the list
// so run the test now
result = TestRsaEncryptDecrypt(alg, toTest);
// if not running the test now, leave the bit on, just in case things
// get interrupted
break;
case ALG_OAEP_VALUE:
case ALG_RSAES_VALUE:
result = TestRsaEncryptDecrypt(alg, toTest);
break;
case ALG_RSAPSS_VALUE:
case ALG_RSASSA_VALUE:
result = TestRsaSignAndVerify(alg, toTest);
break;
default:
SELF_TEST_FAILURE;
}
return result;
}
#endif // TPM_ALG_RSA
//** ECC Tests
#ifdef TPM_ALG_ECC
//*** LoadEccParameter()
// This function is mostly for readability and type checking
static void
LoadEccParameter(
TPM2B_ECC_PARAMETER *to, // target
const TPM2B_EC_TEST *from // source
)
{
MemoryCopy2B(&to->b, &from->b, sizeof(to->t.buffer));
}
//*** LoadEccPoint()
static void
LoadEccPoint(
TPMS_ECC_POINT *point, // target
const TPM2B_EC_TEST *x, // source
const TPM2B_EC_TEST *y
)
{
MemoryCopy2B(&point->x.b, (TPM2B *)x, sizeof(point->x.t.buffer));
MemoryCopy2B(&point->y.b, (TPM2B *)y, sizeof(point->y.t.buffer));
}
//*** TestECDH()
// This test does a KVT on a point multiply.
static TPM_RC
TestECDH(
TPM_ALG_ID scheme, // IN: for consistency
ALGORITHM_VECTOR *toTest // IN/OUT: modified after test is run
)
{
TPMS_ECC_POINT Z;
TPMS_ECC_POINT Qe;
TPM2B_ECC_PARAMETER ds;
TPM_RC result = TPM_RC_SUCCESS;
//
NOT_REFERENCED(scheme);
CLEAR_BOTH(ALG_ECDH_VALUE);
LoadEccParameter(&ds, &c_ecTestKey_ds);
LoadEccPoint(&Qe, &c_ecTestKey_QeX, &c_ecTestKey_QeY);
if(TPM_RC_SUCCESS != CryptEccPointMultiply(&Z, c_testCurve, &Qe, &ds,
NULL, NULL))
SELF_TEST_FAILURE;
if(!MemoryEqual2B(&c_ecTestEcdh_X.b, &Z.x.b)
|| !MemoryEqual2B(&c_ecTestEcdh_Y.b, &Z.y.b))
SELF_TEST_FAILURE;
return result;
}
static TPM_RC
TestEccSignAndVerify(
TPM_ALG_ID scheme,
ALGORITHM_VECTOR *toTest
)
{
OBJECT testObject;
TPMT_SIGNATURE testSig;
TPMT_ECC_SCHEME eccScheme;
testSig.sigAlg = scheme;
testSig.signature.ecdsa.hash = DEFAULT_TEST_HASH;
eccScheme.scheme = scheme;
eccScheme.details.anySig.hashAlg = DEFAULT_TEST_HASH;
CLEAR_BOTH(scheme);
CLEAR_BOTH(ALG_ECDH_VALUE);
// ECC signature verification testing uses a KVT.
switch(scheme)
{
case ALG_ECDSA_VALUE:
LoadEccParameter(&testSig.signature.ecdaa.signatureR, &c_TestEcDsa_r);
LoadEccParameter(&testSig.signature.ecdaa.signatureS, &c_TestEcDsa_s);
break;
case ALG_ECSCHNORR_VALUE:
LoadEccParameter(&testSig.signature.ecdaa.signatureR,
&c_TestEcSchnorr_r);
LoadEccParameter(&testSig.signature.ecdaa.signatureS,
&c_TestEcSchnorr_s);
break;
case ALG_SM2_VALUE:
// don't have a test for SM2
return TPM_RC_SUCCESS;
default:
SELF_TEST_FAILURE;
break;
}
TEST_DEFAULT_TEST_HASH(toTest);
// Have to copy the key. This is because the size used in the test vectors
// is the size of the ECC parameter for the test key while the size of a point
// is TPM dependent
MemoryCopy2B(&testObject.sensitive.sensitive.ecc.b, &c_ecTestKey_ds.b,
sizeof(testObject.sensitive.sensitive.ecc.t.buffer));
LoadEccPoint(&testObject.publicArea.unique.ecc, &c_ecTestKey_QsX,
&c_ecTestKey_QsY);
testObject.publicArea.parameters.eccDetail.curveID = c_testCurve;
if(TPM_RC_SUCCESS != CryptEccValidateSignature(&testSig, &testObject,
(TPM2B_DIGEST *)&c_ecTestValue.b))
{
//??? Don't have a valid test for ECSCORR right now because the algorithm has
//??? changed and the KVT has not been updated.
if(scheme != ALG_ECSCHNORR_VALUE)
SELF_TEST_FAILURE;
}
CHECK_CANCELED;
// Now sign and verify some data
if(TPM_RC_SUCCESS != CryptEccSign(&testSig, &testObject,
(TPM2B_DIGEST *)&c_ecTestValue,
&eccScheme, NULL))
SELF_TEST_FAILURE;
CHECK_CANCELED;
if(TPM_RC_SUCCESS != CryptEccValidateSignature(&testSig, &testObject,
(TPM2B_DIGEST *)&c_ecTestValue))
SELF_TEST_FAILURE;
CHECK_CANCELED;
return TPM_RC_SUCCESS;
}
static TPM_RC
TestEcc(
TPM_ALG_ID alg,
ALGORITHM_VECTOR *toTest
)
{
TPM_RC result = TPM_RC_SUCCESS;
NOT_REFERENCED(toTest);
switch(alg)
{
case ALG_ECC_VALUE:
case ALG_ECDH_VALUE:
// If this is in a loop then see if another test is going to deal with
// this.
// If toTest is not a self-test list
if((toTest == &g_toTest)
// or this is the only ECC test in the list
|| !(TEST_BIT(ALG_ECDSA_VALUE, *toTest)
|| TEST_BIT(ALG_ECSCHNORR, *toTest)
|| TEST_BIT(ALG_SM2_VALUE, *toTest)))
{
result = TestECDH(alg, toTest);
}
break;
case ALG_ECDSA_VALUE:
case ALG_ECSCHNORR_VALUE:
case ALG_SM2_VALUE:
result = TestEccSignAndVerify(alg, toTest);
break;
default:
SELF_TEST_FAILURE;
break;
}
return result;
}
#endif // TPM_ALG_ECC
//*** TestAlgorithm()
// Dispatches to the correct test function for the algorithm or get a list of
// testable algorithms.
//
// If 'toTest' is not NULL, then the test decisions are based on the algorithm
// selections in 'toTest'. Otherwise, 'g_toTest' is used. When bits are clear in
// 'g_toTest' they will also be cleared 'toTest'.
//
// If there doesn't happen to be a test for the algorithm, its associated bit is
// quietly cleared.
//
// If 'alg' is zero (TPM_ALG_ERROR), then the toTest vector is cleared of any bits
// for which there is no test (i.e. no tests are actually run but the vector is
// cleared).
//
// Note: 'toTest' will only ever have bits set for implemented algorithms but 'alg'
// can be anything.
// return type: TPM_RC
// TPM_RC_SUCCESS test complete
// TPM_RC_CANCELED test was canceled
LIB_EXPORT
TPM_RC
TestAlgorithm(
TPM_ALG_ID alg,
ALGORITHM_VECTOR *toTest
)
{
TPM_ALG_ID first = (alg == TPM_ALG_ERROR) ? TPM_ALG_FIRST : alg;
TPM_ALG_ID last = (alg == TPM_ALG_ERROR) ? TPM_ALG_LAST : alg;
BOOL doTest = (alg != TPM_ALG_ERROR);
TPM_RC result = TPM_RC_SUCCESS;
if(toTest == NULL)
toTest = &g_toTest;
// This is kind of strange. This function will either run a test of the selected
// algorithm or just clear a bit if there is no test for the algorithm. So,
// either this loop will be executed once for the selected algorithm or once for
// each of the possible algorithms. If it is executed more than once ('alg' ==
// TPM_ALG_ERROR), then no test will be run but bits will be cleared for
// unimplemented algorithms. This was done this way so that there is only one
// case statement with all of the algorithms. It was easier to have one case
// statement than to have multiple ones to manage whenever an algorithm ID is
// added.
for(alg = first; (alg <= last); alg++)
{
// if 'alg' was TPM_ALG_ERROR, then we will be cycling through
// values, some of which may not be implemented. If the bit in toTest
// happens to be set, then we could either generated an assert, or just
// silently CLEAR it. Decided to just clear.
if(!TEST_BIT(alg, g_implementedAlgorithms))
{
CLEAR_BIT(alg, *toTest);
continue;
}
// Process whatever is left.
// NOTE: since this switch will only be called if the algorithm is
// implemented, it is not necessary to modify this list except to comment
// out the algorithms for which there is no test
switch(alg)
{
// Symmetric block ciphers
#ifdef TPM_ALG_AES
case ALG_AES_VALUE:
#endif
#ifdef TPM_ALG_SM4
// if SM4 is implemented, its test is like other block ciphers but there
// aren't any test vectors for it yet
// case ALG_SM4_VALUE:
#endif
#ifdef TPM_ALG_CAMELLIA
// no test vectors for camellia
// case ALG_CAMELLIA_VALUE:
#endif
// Symmetric modes
#ifndef TPM_ALG_CFB
# error CFB is required in all TPM implementations
#endif // !TPM_ALG_CFB
case ALG_CFB_VALUE:
if(doTest)
result = TestSymmetric(alg, toTest);
break;
#ifdef TPM_ALG_CTR
case ALG_CTR_VALUE:
#endif // TPM_ALG_CRT
#ifdef TPM_ALG_OFB
case ALG_OFB_VALUE:
#endif // TPM_ALG_OFB
#ifdef TPM_ALG_CBC
case ALG_CBC_VALUE:
#endif // TPM_ALG_CBC
#ifdef TPM_ALG_ECB
case ALG_ECB_VALUE:
#endif
if(doTest)
result = TestSymmetric(alg, toTest);
else
// If doing the initialization of g_toTest vector, only need
// to test one of the modes for the symmetric algorithms. If
// initializing for a SelfTest(FULL_TEST), allow all the modes.
if(toTest == &g_toTest)
CLEAR_BIT(alg, *toTest);
break;
#ifndef TPM_ALG_HMAC
# error HMAC is required in all TPM implementations
#endif
case ALG_HMAC_VALUE:
// Clear the bit that indicates that HMAC is required because
// HMAC is used as the basic test for all hash algorithms.
CLEAR_BOTH(alg);
// Testing HMAC means test the default hash
if(doTest)
TestHash(DEFAULT_TEST_HASH, toTest);
else
// If not testing, then indicate that the hash needs to be
// tested because this uses HMAC
SET_BOTH(DEFAULT_TEST_HASH);
break;
#ifdef TPM_ALG_SHA1
case ALG_SHA1_VALUE:
#endif // TPM_ALG_SHA1
#ifdef TPM_ALG_SHA256
case ALG_SHA256_VALUE:
#endif // TPM_ALG_SHA256
#ifdef TPM_ALG_SHA384
case ALG_SHA384_VALUE:
#endif // TPM_ALG_SHA384
#ifdef TPM_ALG_SHA512
case ALG_SHA512_VALUE:
#endif // TPM_ALG_SHA512
// if SM3 is implemented its test is like any other hash, but there
// aren't any test vectors yet.
#ifdef TPM_ALG_SM3_256
// case ALG_SM3_256_VALUE:
#endif // TPM_ALG_SM3_256
if(doTest)
result = TestHash(alg, toTest);
break;
// RSA-dependent
#ifdef TPM_ALG_RSA
case ALG_RSA_VALUE:
CLEAR_BOTH(alg);
if(doTest)
result = TestRsa(TPM_ALG_NULL, toTest);
else
SET_BOTH(TPM_ALG_NULL);
break;
case ALG_RSASSA_VALUE:
case ALG_RSAES_VALUE:
case ALG_RSAPSS_VALUE:
case ALG_OAEP_VALUE:
case ALG_NULL_VALUE: // used or RSADP
if(doTest)
result = TestRsa(alg, toTest);
break;
#endif // TPM_ALG_RSA
#ifdef TPM_ALG_ECC
// ECC dependent but no tests
// case ALG_ECDAA_VALUE:
// case ALG_ECMQV_VALUE:
// case ALG_KDF1_SP800_56a_VALUE:
// case ALG_KDF2_VALUE:
// case ALG_KDF1_SP800_108_VALUE:
// case ALG_MGF1_VALUE:
case ALG_ECC_VALUE:
CLEAR_BOTH(alg);
if(doTest)
result = TestEcc(ALG_ECDH_VALUE, toTest);
else
SET_BOTH(ALG_ECDH_VALUE);
break;
case ALG_ECDSA_VALUE:
case ALG_ECDH_VALUE:
case ALG_ECSCHNORR_VALUE:
// case ALG_SM2_VALUE:
if(doTest)
result = TestEcc(alg, toTest);
break;
#endif // TPM_ALG_ECC
default:
CLEAR_BIT(alg, *toTest);
break;
}
if(result != TPM_RC_SUCCESS)
break;
}
return result;
}
#endif // SELF_TESTS