tpm2: Implement functions to set and check runtime-disabled algorithms

Implement functions to set and check runtime-disabled algorithms. Use
these functions when the algorithm capabilities of the TPM 2 are
advertised via the TPM2_GetCapability command. However, it is not
sufficient to just suppress runtime-disabled algorithms in the return
value of this command but also certain code paths have to be instrumented
to check for disabled algorithms since they could otherwise lead to their
usage. Users are not required nor will they always look at the returned
values of TPM2_GetCapability but should still be prevented from using
runtime-disabled algorithms.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
This commit is contained in:
Stefan Berger 2022-06-07 12:07:01 -04:00 committed by Stefan Berger
parent 3aea409f92
commit 63f4981309
3 changed files with 822 additions and 0 deletions

View File

@ -296,6 +296,7 @@ libtpms_tpm2_la_SOURCES = \
tpm2/BackwardsCompatibilityObject.c \
tpm2/LibtpmsCallbacks.c \
tpm2/NVMarshal.c \
tpm2/RuntimeAlgorithm.c \
tpm2/StateMarshal.c \
tpm2/Volatile.c
@ -566,6 +567,7 @@ noinst_HEADERS += \
tpm2/BackwardsCompatibilityObject.h \
tpm2/LibtpmsCallbacks.h \
tpm2/NVMarshal.h \
tpm2/RuntimeAlgorithm_fp.h \
tpm2/StateMarshal.h \
tpm2/Utils.h \
tpm2/Volatile.h

714
src/tpm2/RuntimeAlgorithm.c Normal file
View File

@ -0,0 +1,714 @@
/********************************************************************************/
/* */
/* Algorithm Runtime Disablement */
/* Written by Stefan Berger */
/* IBM Thomas J. Watson Research Center */
/* */
/* Licenses and Notices */
/* */
/* (c) Copyright IBM Corporation, 2022 */
/* */
/* All rights reserved. */
/* */
/* 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. */
/* */
/* Neither the names of the IBM Corporation nor the names of its */
/* contributors may be used to endorse or promote products derived from */
/* this software without specific prior written permission. */
/* */
/* 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. */
/* */
/********************************************************************************/
#define _GNU_SOURCE
#include <assert.h>
#include <string.h>
#include "RuntimeAlgorithm_fp.h"
#include "NVMarshal.h"
#include "GpMacros.h"
#include "tpm_library_intern.h"
#define ALGO_SEPARATOR_C ','
#define ALGO_SEPARATOR_STR ","
struct KeySizes {
BOOL enabled;
UINT16 size;
unsigned int stateFormatLevel; /* required stateFormatLevel to support this */
};
static const struct KeySizes s_KeySizesAES[] = {
{ .enabled = AES_128, .size = 128, .stateFormatLevel = 1 },
{ .enabled = AES_192, .size = 192, .stateFormatLevel = 0 }, // not supported
{ .enabled = AES_256, .size = 256, .stateFormatLevel = 1 },
{ .enabled = false , .size = 0 , .stateFormatLevel = 0 },
};
static const struct KeySizes s_KeySizesSM4[] = {
{ .enabled = SM4_128, .size = 128, .stateFormatLevel = 0 }, // not supported
{ .enabled = false , .size = 0 , .stateFormatLevel = 0 },
};
static const struct KeySizes s_KeySizesCamellia[] = {
{ .enabled = CAMELLIA_128, .size = 128, .stateFormatLevel = 1 },
{ .enabled = CAMELLIA_192, .size = 192, .stateFormatLevel = 0 }, // not supported
{ .enabled = CAMELLIA_256, .size = 256, .stateFormatLevel = 1 },
{ .enabled = false , .size = 0 , .stateFormatLevel = 0 },
};
static const struct KeySizes s_KeySizesTDES[] = {
{ .enabled = TDES_128, .size = 128, .stateFormatLevel = 1 },
{ .enabled = TDES_192, .size = 192, .stateFormatLevel = 1 },
{ .enabled = false , .size = 0 , .stateFormatLevel = 0 },
};
static const struct KeySizes s_KeySizesRSA[] = {
{ .enabled = RSA_1024, .size = 1024, .stateFormatLevel = 1 },
{ .enabled = RSA_2048, .size = 2048, .stateFormatLevel = 1 },
{ .enabled = RSA_3072, .size = 3072, .stateFormatLevel = 1 },
{ .enabled = false , .size = 0 , .stateFormatLevel = 0 },
};
static const struct KeySizes s_KeySizesECC[] = {
{ .enabled = ECC_NIST_P192, .size = 192, .stateFormatLevel = 1 },
{ .enabled = ECC_NIST_P224, .size = 224, .stateFormatLevel = 1 },
{ .enabled = ECC_NIST_P256, .size = 256, .stateFormatLevel = 1 },
{ .enabled = ECC_BN_P256 , .size = 256, .stateFormatLevel = 1 },
{ .enabled = ECC_SM2_P256 , .size = 256, .stateFormatLevel = 1 },
{ .enabled = ECC_NIST_P384, .size = 384, .stateFormatLevel = 1 },
{ .enabled = ECC_NIST_P521, .size = 521, .stateFormatLevel = 1 },
{ .enabled = ECC_BN_P638 , .size = 638, .stateFormatLevel = 1 },
{ .enabled = false , .size = 0 , .stateFormatLevel = 0 },
};
static const struct {
const char *name;
union {
const struct KeySizes *keySizes;
} u;
BOOL canBeDisabled;
unsigned int stateFormatLevel; /* required stateFormatLevel to support this */
} s_AlgorithmProperties[NUM_ENTRIES_ALGORITHM_PROPERTIES] = {
#define SYMMETRIC(ENABLED, NAME, KEYSIZES, CANDISABLE, SFL) \
{ .name = ENABLED ? NAME : NULL, .u.keySizes = KEYSIZES, .canBeDisabled = CANDISABLE, .stateFormatLevel = SFL }
#define ASYMMETRIC(ENABLED, NAME, KEYSIZES, CANDISABLE, SFL) \
{ .name = ENABLED ? NAME : NULL, .u.keySizes = KEYSIZES, .canBeDisabled = CANDISABLE, .stateFormatLevel = SFL }
#define HASH(ENABLED, NAME, CANDISABLE, SFL) \
{ .name = ENABLED ? NAME : NULL, .canBeDisabled = CANDISABLE, .stateFormatLevel = SFL }
#define SIGNING(ENABLED, NAME, CANDISABLE, SFL) \
{ .name = ENABLED ? NAME : NULL, .canBeDisabled = CANDISABLE, .stateFormatLevel = SFL }
#define ENCRYPTING(ENABLED, NAME, CANDISABLE, SFL) \
{ .name = ENABLED ? NAME : NULL, .canBeDisabled = CANDISABLE, .stateFormatLevel = SFL }
#define OTHER(ENABLED, NAME, CANDISABLE, SFL) \
{ .name = ENABLED ? NAME : NULL, .canBeDisabled = CANDISABLE, .stateFormatLevel = SFL }
[TPM_ALG_RSA] = ASYMMETRIC(ALG_RSA, "rsa", s_KeySizesRSA, false, 1),
[TPM_ALG_TDES] = SYMMETRIC(ALG_TDES, "tdes", s_KeySizesTDES, false, 1),
[TPM_ALG_SHA1] = HASH(ALG_SHA1, "sha1", false, 1),
[TPM_ALG_HMAC] = SIGNING(ALG_HMAC, "hmac", false, 1),
[TPM_ALG_AES] = SYMMETRIC(ALG_AES, "aes", s_KeySizesAES, false, 1), // never disable: context encryption
[TPM_ALG_MGF1] = HASH(ALG_MGF1, "mgf1", false, 1),
[TPM_ALG_KEYEDHASH] = HASH(ALG_KEYEDHASH, "keyedhash", false, 1),
[TPM_ALG_XOR] = OTHER(ALG_XOR, "xor", false, 1),
[TPM_ALG_SHA256] = HASH(ALG_SHA256, "sha256", false, 1),
[TPM_ALG_SHA384] = HASH(ALG_SHA384, "sha384", false, 1),
[TPM_ALG_SHA512] = HASH(ALG_SHA512, "sha512", false, 1),
[TPM_ALG_NULL] = OTHER(true, "null", false, 1),
[TPM_ALG_SM4] = SYMMETRIC(ALG_SM4, "sm4", s_KeySizesSM4, false, 0), // not supported
[TPM_ALG_RSASSA] = SIGNING(ALG_RSASSA, "rsassa", false, 1),
[TPM_ALG_RSAES] = ENCRYPTING(ALG_RSAES, "rsaes", false, 1),
[TPM_ALG_RSAPSS] = SIGNING(ALG_RSAPSS, "rsapss", false, 1),
[TPM_ALG_OAEP] = ENCRYPTING(ALG_OAEP, "oaep", false, 1), // never disable: CryptSecretEncrypt/Decrypt needs it
[TPM_ALG_ECDSA] = SIGNING(ALG_ECDSA, "ecdsa", false, 1),
[TPM_ALG_ECDH] = OTHER(ALG_ECDH, "ecdh", false, 1),
[TPM_ALG_ECDAA] = OTHER(ALG_ECDAA, "ecdaa", false, 1),
[TPM_ALG_SM2] = SIGNING(ALG_SM2, "sm2", false, 1),
[TPM_ALG_ECSCHNORR] = SIGNING(ALG_ECSCHNORR, "ecschnorr", false, 1),
[TPM_ALG_ECMQV] = OTHER(ALG_ECMQV, "ecmqv", false, 1),
[TPM_ALG_KDF1_SP800_56A] = HASH(ALG_KDF1_SP800_56A, "kdf1-sp800-56a", false, 1),
[TPM_ALG_KDF2] = HASH(ALG_KDF2, "kdf2", false, 1),
[TPM_ALG_KDF1_SP800_108] = HASH(ALG_KDF1_SP800_108, "kdf1-sp800-108", false, 1),
[TPM_ALG_ECC] = ASYMMETRIC(ALG_ECC, "ecc", s_KeySizesECC, false, 1),
[TPM_ALG_SYMCIPHER] = OTHER(ALG_SYMCIPHER, "symcipher", false, 1),
[TPM_ALG_CAMELLIA] = SYMMETRIC(ALG_CAMELLIA, "camellia", s_KeySizesCamellia, false, 1),
[TPM_ALG_SHA3_256] = HASH(ALG_SHA3_256, "sha3-256", false, 0), // not supported
[TPM_ALG_SHA3_384] = HASH(ALG_SHA3_384, "sha3-384", false, 0), // not supported
[TPM_ALG_SHA3_512] = HASH(ALG_SHA3_512, "sha3-256", false, 0), // not supported
[TPM_ALG_CMAC] = SIGNING(ALG_CMAC, "cmac", false, 1),
[TPM_ALG_CTR] = ENCRYPTING(ALG_CTR, "ctr", false, 1),
[TPM_ALG_OFB] = ENCRYPTING(ALG_OFB, "ofb", false, 1),
[TPM_ALG_CBC] = ENCRYPTING(ALG_CBC, "cbc", false, 1),
[TPM_ALG_CFB] = ENCRYPTING(ALG_CFB, "cfb", false, 1), // never disable: context entryption
[TPM_ALG_ECB] = ENCRYPTING(ALG_ECB, "ecb", false, 1),
};
static const struct {
const char *name;
BOOL canBeDisabled;
const char *prefix;
} s_EccShortcuts[] = {
#define ECC_SHORTCUT(NAME, CANDISABLE, PREFIX) \
{ .name = NAME, .canBeDisabled = CANDISABLE, .prefix = PREFIX }
[RUNTIME_ALGORITHM_ECC_NIST_BIT] = ECC_SHORTCUT("ecc-nist", true, "ecc-nist-p"),
[RUNTIME_ALGORITHM_ECC_BN_BIT] = ECC_SHORTCUT("ecc-bn", true, "ecc-bn-p"),
};
static const struct {
const char *name;
UINT16 keySize;
BOOL canBeDisabled;
unsigned int stateFormatLevel; /* required stateFormatLevel to support this */
} s_EccAlgorithmProperties[] = {
#define ECC(ENABLED, NAME, KEYSIZE, CANDISABLE, SFL) \
{ .name = ENABLED ? NAME : NULL, .keySize = KEYSIZE, .canBeDisabled = CANDISABLE, .stateFormatLevel = SFL }
[TPM_ECC_NIST_P192] = ECC(ECC_NIST_P192, "ecc-nist-p192", 192, true, 1),
[TPM_ECC_NIST_P224] = ECC(ECC_NIST_P224, "ecc-nist-p224", 224, true, 1),
[TPM_ECC_NIST_P256] = ECC(ECC_NIST_P256, "ecc-nist-p256", 256, false, 1),
[TPM_ECC_NIST_P384] = ECC(ECC_NIST_P384, "ecc-nist-p384", 384, false, 1),
[TPM_ECC_NIST_P521] = ECC(ECC_NIST_P521, "ecc-nist-p521", 521, true, 1),
[TPM_ECC_BN_P256] = ECC(ECC_BN_P256, "ecc-bn-p256", 256, true, 1),
[TPM_ECC_BN_P638] = ECC(ECC_BN_P638, "ecc-bn-p638", 638, true, 1),
[TPM_ECC_SM2_P256] = ECC(ECC_SM2_P256, "ecc-sm2-p256", 256, true, 1),
};
static const TPM_ALG_ID algsWithKeySizes[] = {
TPM_ALG_RSA,
TPM_ALG_TDES,
TPM_ALG_AES,
TPM_ALG_SM4,
TPM_ALG_CAMELLIA,
};
static unsigned int
KeySizesGetMinimum(const struct KeySizes *ks)
{
size_t i = 0;
while (ks[i].size) {
if (ks[i].enabled)
return ks[i].size;
i++;
}
return 0;
}
static void
RuntimeAlgorithmEnableAllAlgorithms(struct RuntimeAlgorithm *RuntimeAlgorithm)
{
TPM_ECC_CURVE curveId;
TPM_ALG_ID algId;
MemorySet(RuntimeAlgorithm->enabledAlgorithms, 0 , sizeof(RuntimeAlgorithm->enabledAlgorithms));
for (algId = 0; algId < ARRAY_SIZE(s_AlgorithmProperties); algId++) {
/* skip over unsupported algorithms */
if (!s_AlgorithmProperties[algId].name)
continue;
SET_BIT(algId, RuntimeAlgorithm->enabledAlgorithms);
}
MemorySet(RuntimeAlgorithm->enabledEccCurves, 0 , sizeof(RuntimeAlgorithm->enabledEccCurves));
MemorySet(RuntimeAlgorithm->enabledEccCurvesPrint, 0 , sizeof(RuntimeAlgorithm->enabledEccCurvesPrint));
for (curveId = 0; curveId < ARRAY_SIZE(s_EccAlgorithmProperties); curveId++) {
if (!s_EccAlgorithmProperties[curveId].name)
continue;
SET_BIT(curveId, RuntimeAlgorithm->enabledEccCurves);
}
}
LIB_EXPORT void
RuntimeAlgorithmInit(struct RuntimeAlgorithm *RuntimeAlgorithm)
{
TPM_ALG_ID algId;
size_t i;
MemorySet(RuntimeAlgorithm->algosMinimumKeySizes, 0 , sizeof(RuntimeAlgorithm->algosMinimumKeySizes));
for (i = 0; i < ARRAY_SIZE(algsWithKeySizes); i++) {
algId = algsWithKeySizes[i];
assert(algId < ARRAY_SIZE(RuntimeAlgorithm->algosMinimumKeySizes));
assert(s_AlgorithmProperties[algId].u.keySizes != NULL);
RuntimeAlgorithm->algosMinimumKeySizes[algId] = KeySizesGetMinimum(s_AlgorithmProperties[algId].u.keySizes);
}
}
LIB_EXPORT void
RuntimeAlgorithmFree(struct RuntimeAlgorithm *RuntimeAlgorithm)
{
free(RuntimeAlgorithm->algorithmProfile);
RuntimeAlgorithm->algorithmProfile = NULL;
}
/* Set the default profile with all algorithms and all keysizes enabled */
static void
RuntimeAlgorithmSetDefault(struct RuntimeAlgorithm *RuntimeAlgorithm)
{
RuntimeAlgorithmFree(RuntimeAlgorithm);
RuntimeAlgorithmInit(RuntimeAlgorithm);
RuntimeAlgorithmEnableAllAlgorithms(RuntimeAlgorithm);
}
/* Set the given profile and runtime-enable the given algorithms. A NULL pointer
* for the profile parameter sets the default profile which enables all algorithms
* and all key sizes without any restrictions.
*
* This function will adjust the stateFormatLevel to the number required for the
* given algorithms and key sizes.
*/
LIB_EXPORT TPM_RC
RuntimeAlgorithmSetProfile(struct RuntimeAlgorithm *RuntimeAlgorithm,
const char *newProfile, // IN: colon-separated list of algorithm names
unsigned int *stateFormatLevel, // IN/OUT: stateFormatLevel
unsigned int maxStateFormatLevel // IN: maximum allowed stateFormatLevel
)
{
size_t toklen, cmplen, i, prefix_len, idx;
const char *token, *comma, *prefix;
const struct KeySizes *keysizes;
TPM_RC retVal = TPM_RC_SUCCESS;
unsigned long minKeySize;
TPM_ECC_CURVE curveId;
TPM_ALG_ID algId;
char *endptr;
bool found;
/* NULL pointer for profile enables all */
if (!newProfile) {
RuntimeAlgorithmSetDefault(RuntimeAlgorithm);
return TPM_RC_SUCCESS;
}
MemorySet(RuntimeAlgorithm->enabledAlgorithms, 0, sizeof(RuntimeAlgorithm->enabledAlgorithms));
MemorySet(RuntimeAlgorithm->enabledEccCurves, 0 , sizeof(RuntimeAlgorithm->enabledEccCurves));
MemorySet(RuntimeAlgorithm->enabledEccCurvesPrint, 0 , sizeof(RuntimeAlgorithm->enabledEccCurvesPrint));
MemorySet(RuntimeAlgorithm->enabledEccShortcuts, 0, sizeof(RuntimeAlgorithm->enabledEccShortcuts));
token = newProfile;
while (1) {
comma = strchr(token, ALGO_SEPARATOR_C);
if (comma)
toklen = (size_t)(comma - token);
else
toklen = strlen(token);
found = false;
for (algId = 0; algId < ARRAY_SIZE(s_AlgorithmProperties); algId++) {
/* skip over unsupported algorithms */
if (!s_AlgorithmProperties[algId].name)
continue;
cmplen = MAX(strlen(s_AlgorithmProperties[algId].name), toklen);
if (!strncmp(token, s_AlgorithmProperties[algId].name, cmplen)) {
if (s_AlgorithmProperties[algId].stateFormatLevel > maxStateFormatLevel) {
TPMLIB_LogTPM2Error("Requested algorithm %.*s requires StateFormatLevel %u but maximum allowed is %u.\n",
(int)toklen, token,
s_AlgorithmProperties[algId].stateFormatLevel,
maxStateFormatLevel);
retVal = TPM_RC_VALUE;
goto exit;
}
SET_BIT(algId, RuntimeAlgorithm->enabledAlgorithms);
assert(s_AlgorithmProperties[algId].stateFormatLevel > 0);
*stateFormatLevel = MAX(*stateFormatLevel,
s_AlgorithmProperties[algId].stateFormatLevel);
found = true;
break;
} else if (s_AlgorithmProperties[algId].u.keySizes) {
size_t algnamelen = strlen(s_AlgorithmProperties[algId].name);
if (strncmp(token, s_AlgorithmProperties[algId].name, algnamelen) ||
strncmp(&token[algnamelen], "-min-size=", 10))
continue;
minKeySize = strtoul(&token[algnamelen + 10], &endptr, 10);
if ((*endptr != ALGO_SEPARATOR_C && *endptr != '\0') || minKeySize > 4096) {
retVal = TPM_RC_KEY_SIZE;
goto exit;
}
/* determine stateFormatLevel needed; skip those key sizes that exceed max. stateFormatLevel */
keysizes = s_AlgorithmProperties[algId].u.keySizes;
for (i = 0; keysizes[i].size != 0; i++) {
if (keysizes[i].enabled &&
keysizes[i].size >= minKeySize &&
keysizes[i].stateFormatLevel <= maxStateFormatLevel) {
assert(keysizes[i].stateFormatLevel > 0);
*stateFormatLevel = MAX(*stateFormatLevel,
keysizes[i].stateFormatLevel);
}
}
RuntimeAlgorithm->algosMinimumKeySizes[algId] = (UINT16)minKeySize;
found = true;
break;
}
}
if (!found) {
bool match_one = true;
/* handling of ECC curves: shortcuts */
for (idx = 0; idx < ARRAY_SIZE(s_EccShortcuts); idx++) {
cmplen = MAX(strlen(s_EccShortcuts[idx].name), toklen);
if (!strncmp(token, s_EccShortcuts[idx].name, cmplen)) {
SET_BIT(idx, RuntimeAlgorithm->enabledEccShortcuts);
match_one = false;
prefix = s_EccShortcuts[idx].prefix;
prefix_len = strlen(prefix);
break;
}
}
if (match_one) {
prefix = token;
prefix_len = toklen;
}
for (curveId = 0; curveId < ARRAY_SIZE(s_EccAlgorithmProperties); curveId++) {
if (!s_EccAlgorithmProperties[curveId].name)
continue;
if (match_one)
cmplen = MAX(strlen(s_EccAlgorithmProperties[curveId].name), toklen);
else
cmplen = prefix_len;
if (!strncmp(prefix, s_EccAlgorithmProperties[curveId].name, cmplen)) {
if (s_EccAlgorithmProperties[curveId].stateFormatLevel > maxStateFormatLevel) {
/* specific match that is not allowed causes error, otherwise skip */
if (match_one) {
TPMLIB_LogTPM2Error("Requested curve %s requires StateFormatLevel %u but maximum allowed is %u.\n",
s_EccAlgorithmProperties[curveId].name,
s_EccAlgorithmProperties[curveId].stateFormatLevel,
maxStateFormatLevel);
retVal = TPM_RC_FAILURE;
goto exit;
}
continue;
}
*stateFormatLevel = MAX(*stateFormatLevel,
s_EccAlgorithmProperties[curveId].stateFormatLevel);
SET_BIT(curveId, RuntimeAlgorithm->enabledEccCurves);
found = true;
if (match_one) {
SET_BIT(curveId, RuntimeAlgorithm->enabledEccCurvesPrint);
break;
}
}
}
}
if (!found) {
TPMLIB_LogTPM2Error("Requested algorithm specifier %.*s is not supported.\n",
(int)toklen, token);
retVal = TPM_RC_FAILURE;
goto exit;
}
if (!comma)
break;
token = &comma[1];
}
/* reconcile with what can be disabled per code instrumentation */
for (algId = 0; algId < ARRAY_SIZE(s_AlgorithmProperties); algId++) {
/* skip over unsupported algorithms */
if (!s_AlgorithmProperties[algId].name)
continue;
if (!s_AlgorithmProperties[algId].canBeDisabled &&
!TEST_BIT(algId, RuntimeAlgorithm->enabledAlgorithms)) {
TPMLIB_LogTPM2Error("Algorithm %s must be enabled.\n",
s_AlgorithmProperties[algId].name);
retVal = TPM_RC_FAILURE;
goto exit;
}
}
for (curveId = 0; curveId < ARRAY_SIZE(s_EccAlgorithmProperties); curveId++) {
if (!s_EccAlgorithmProperties[curveId].name)
continue;
if (!s_EccAlgorithmProperties[curveId].canBeDisabled &&
!TEST_BIT(curveId, RuntimeAlgorithm->enabledEccCurves)) {
TPMLIB_LogTPM2Error("Elliptic curve %s must be enabled.\n",
s_EccAlgorithmProperties[curveId].name);
retVal = TPM_RC_FAILURE;
goto exit;
}
}
/* some consistency checks */
/* Do not allow aes-min-size > 128 while RSA=2048 otherwise standard EK certs cannot be created anymore */
if (RuntimeAlgorithm->algosMinimumKeySizes[TPM_ALG_AES] > 128 &&
RuntimeAlgorithm->algosMinimumKeySizes[TPM_ALG_RSA] == 2048) {
TPMLIB_LogTPM2Error("AES minimum key size must be 128 when "
"2048 bit %s keys are used.\n",
"RSA");
retVal = TPM_RC_KEY_SIZE;
goto exit;
}
free(RuntimeAlgorithm->algorithmProfile);
RuntimeAlgorithm->algorithmProfile = strdup(newProfile);
if (!RuntimeAlgorithm->algorithmProfile)
retVal = TPM_RC_MEMORY;
exit:
if (retVal != TPM_RC_SUCCESS)
RuntimeAlgorithmSetDefault(RuntimeAlgorithm);
return retVal;
}
LIB_EXPORT TPM_RC
RuntimeAlgorithmSwitchProfile(struct RuntimeAlgorithm *RuntimeAlgorithm,
const char *newProfile,
unsigned int maxStateFormatLevel,
char **oldProfile)
{
TPM_RC retVal;
unsigned int stateFormatLevel = 0; // ignored
*oldProfile = RuntimeAlgorithm->algorithmProfile;
RuntimeAlgorithm->algorithmProfile = NULL;
retVal = RuntimeAlgorithmSetProfile(RuntimeAlgorithm, newProfile,
&stateFormatLevel, maxStateFormatLevel);
if (retVal != TPM_RC_SUCCESS) {
RuntimeAlgorithmSetProfile(RuntimeAlgorithm, *oldProfile,
&stateFormatLevel, maxStateFormatLevel);
*oldProfile = NULL;
}
return retVal;
}
/* Check whether the given algorithm is runtime-enabled */
LIB_EXPORT BOOL
RuntimeAlgorithmCheckEnabled(struct RuntimeAlgorithm *RuntimeAlgorithm,
TPM_ALG_ID algId // IN: the algorithm to check
)
{
if (!TEST_BIT(algId, RuntimeAlgorithm->enabledAlgorithms))
return FALSE;
return TRUE;
}
/* Check whether the given symmetric or asymmetric crypto algorithm is enabled
* for the given keysize. The maxStateFormatLevel prevents certain key sizes
* from being usable if these were only enabled after the algorithm was enabled.
*
* Example: Algorithm 'x' was enabled but keysize 192 was not enabled at this
* point. The required stateFormatLevel for 'x' is 1. To use keysize 192
* stateFormatLevel '4' is required but due to the profile's stateFormatLevel '1'
* it needs to be filtered-out so that the profile doesn't need an upgrade to
* stateFormatLevel '4'.
*/
LIB_EXPORT BOOL
RuntimeAlgorithmKeySizeCheckEnabled(struct RuntimeAlgorithm *RuntimeAlgorithm,
TPM_ALG_ID algId, // IN: the algorithm to check
UINT16 keySizeInBits, // IN: size of the key in bits
TPM_ECC_CURVE curveId, // IN: curve Id if algId == TPM_ALG_ECC
unsigned int maxStateFormatLevel // IN: maximum stateFormatLevel
)
{
const struct KeySizes *keysizes;
UINT16 minKeySize;
size_t i;
if (!RuntimeAlgorithmCheckEnabled(RuntimeAlgorithm, algId))
return FALSE;
minKeySize = RuntimeAlgorithm->algosMinimumKeySizes[algId];
if (minKeySize > keySizeInBits)
return FALSE;
if (algId == TPM_ALG_ECC) {
if (!TEST_BIT(curveId, RuntimeAlgorithm->enabledEccCurves)) {
return FALSE;
}
}
keysizes = s_AlgorithmProperties[algId].u.keySizes;
for (i = 0; keysizes[i].size != 0; i++) {
if (keysizes[i].size == keySizeInBits) {
if (keysizes[i].enabled &&
keysizes[i].stateFormatLevel > maxStateFormatLevel) {
return FALSE;
}
return TRUE;
}
}
return TRUE;
}
static char *
RuntimeAlgorithmGetEcc(struct RuntimeAlgorithm *RuntimeAlgorithm,
enum RuntimeAlgorithmType rat,
char *buffer)
{
TPM_ECC_CURVE curveId;
char *nbuffer = NULL;
size_t idx;
int n;
for (idx = 0; idx < ARRAY_SIZE(s_EccShortcuts); idx++) {
switch (rat) {
case RUNTIME_ALGO_IMPLEMENTED:
// no filter;
break;
case RUNTIME_ALGO_CAN_BE_DISABLED:
if (!s_EccShortcuts[idx].canBeDisabled)
continue;
break;
case RUNTIME_ALGO_ENABLED:
if (!TEST_BIT(idx, RuntimeAlgorithm->enabledEccShortcuts))
continue;
break;
case RUNTIME_ALGO_DISABLED:
if (TEST_BIT(idx, RuntimeAlgorithm->enabledEccShortcuts))
continue;
break;
default:
break;
}
n = asprintf(&nbuffer, "%s%s%s",
buffer, ALGO_SEPARATOR_STR, s_EccShortcuts[idx].name);
free(buffer);
if (n < 0)
return NULL;
buffer = nbuffer;
}
for (curveId = 0; curveId < ARRAY_SIZE(s_EccAlgorithmProperties); curveId++) {
if (!s_EccAlgorithmProperties[curveId].name)
continue;
switch (rat) {
case RUNTIME_ALGO_IMPLEMENTED:
// no filter
break;
case RUNTIME_ALGO_CAN_BE_DISABLED:
if (!s_EccAlgorithmProperties[curveId].canBeDisabled)
continue;
break;
case RUNTIME_ALGO_ENABLED:
if (!TEST_BIT(curveId, RuntimeAlgorithm->enabledEccCurvesPrint))
continue;
break;
case RUNTIME_ALGO_DISABLED:
if (TEST_BIT(curveId, RuntimeAlgorithm->enabledEccCurvesPrint))
continue;
break;
default:
break;
}
n = asprintf(&nbuffer, "%s%s%s",
buffer, ALGO_SEPARATOR_STR, s_EccAlgorithmProperties[curveId].name);
free(buffer);
if (n < 0)
return NULL;
buffer = nbuffer;
}
return buffer;
}
LIB_EXPORT char *
RuntimeAlgorithmPrint(struct RuntimeAlgorithm *RuntimeAlgorithm,
enum RuntimeAlgorithmType rat)
{
char *buffer, *nbuffer = NULL;
unsigned int minKeySize;
TPM_ALG_ID algId;
int n;
BOOL first = true;
buffer = strdup("\"");
if (!buffer)
return NULL;
for (algId = 0; algId < ARRAY_SIZE(s_AlgorithmProperties); algId++) {
// skip over unsupported algorithms
if (!s_AlgorithmProperties[algId].name)
continue;
switch (rat) {
case RUNTIME_ALGO_IMPLEMENTED:
// no filter
break;
case RUNTIME_ALGO_CAN_BE_DISABLED:
if (!s_AlgorithmProperties[algId].canBeDisabled)
goto skip; // TPM_ALG_ECC: need to print more
break;
case RUNTIME_ALGO_ENABLED:
// skip over disabled ones
if (!RuntimeAlgorithmCheckEnabled(RuntimeAlgorithm, algId))
goto skip;
break;
case RUNTIME_ALGO_DISABLED:
// skip over enabled ones
if (RuntimeAlgorithmCheckEnabled(RuntimeAlgorithm, algId))
goto skip;
break;
default:
continue;
}
n = asprintf(&nbuffer, "%s%s%s",
buffer ? buffer : "",
first ? "" : ALGO_SEPARATOR_STR,
s_AlgorithmProperties[algId].name);
free(buffer);
if (n < 0)
return NULL;
buffer = nbuffer;
first = false;
minKeySize = 0;
switch (rat) {
case RUNTIME_ALGO_IMPLEMENTED:
if (s_AlgorithmProperties[algId].u.keySizes) {
minKeySize = KeySizesGetMinimum(s_AlgorithmProperties[algId].u.keySizes);
}
break;
case RUNTIME_ALGO_ENABLED:
if (s_AlgorithmProperties[algId].u.keySizes) {
minKeySize = RuntimeAlgorithm->algosMinimumKeySizes[algId];
}
break;
default:
break;
}
if (minKeySize > 0) {
n = asprintf(&nbuffer, "%s%s%s-min-size=%u",
buffer,
ALGO_SEPARATOR_STR,
s_AlgorithmProperties[algId].name,
minKeySize);
free(buffer);
if (n < 0)
return NULL;
buffer = nbuffer;
}
skip:
if (algId == TPM_ALG_ECC)
buffer = RuntimeAlgorithmGetEcc(RuntimeAlgorithm, rat, buffer);
}
n = asprintf(&nbuffer, "%s\"", buffer);
free(buffer);
return nbuffer;
}

View File

@ -0,0 +1,106 @@
/********************************************************************************/
/* */
/* Algorithm Runtime Disablement */
/* Written by Stefan Berger */
/* IBM Thomas J. Watson Research Center */
/* */
/* Licenses and Notices */
/* */
/* (c) Copyright IBM Corporation, 2022 */
/* */
/* All rights reserved. */
/* */
/* 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. */
/* */
/* Neither the names of the IBM Corporation nor the names of its */
/* contributors may be used to endorse or promote products derived from */
/* this software without specific prior written permission. */
/* */
/* 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. */
/* */
/********************************************************************************/
#ifndef RUNTIME_ALGORITHM_H
#define RUNTIME_ALGORITHM_H
#include "Tpm.h"
#define NUM_ENTRIES_ALGORITHM_PROPERTIES (size_t)(TPM_ALG_LAST + 1)
#define NUM_ENTRIES_ECC_ALGO_PROPERTIES (size_t)(TPM_ECC_SM2_P256 + 1)
struct RuntimeAlgorithm {
/* array holding minimum key sizes for algorithms in algsWithKeySizes */
UINT16 algosMinimumKeySizes[NUM_ENTRIES_ALGORITHM_PROPERTIES];
ALGORITHM_VECTOR enabledAlgorithms;
unsigned char enabledEccShortcuts[1];
#define RUNTIME_ALGORITHM_ECC_NIST_BIT 0
#define RUNTIME_ALGORITHM_ECC_BN_BIT 1
unsigned char enabledEccCurves[(NUM_ENTRIES_ECC_ALGO_PROPERTIES + 7) / 8];
unsigned char enabledEccCurvesPrint[(NUM_ENTRIES_ECC_ALGO_PROPERTIES + 7) / 8];
char *algorithmProfile;
};
void
RuntimeAlgorithmInit(struct RuntimeAlgorithm *RuntimeAlgorithm);
void
RuntimeAlgorithmFree(struct RuntimeAlgorithm *RuntimeAlgorithm);
TPM_RC
RuntimeAlgorithmSetProfile(struct RuntimeAlgorithm *RuntimeAlgorithm,
const char *newProfile,
unsigned int *stateFormatLevel,
unsigned int maxstateFormatLevel);
TPM_RC
RuntimeAlgorithmSwitchProfile(struct RuntimeAlgorithm *RuntimeAlgorithm,
const char *newProfile,
unsigned int maxStateFormatLevel,
char **oldProfile);
BOOL
RuntimeAlgorithmCheckEnabled(struct RuntimeAlgorithm *RuntimeAlgorithm,
TPM_ALG_ID algId // IN: the algorithm to check
);
BOOL
RuntimeAlgorithmKeySizeCheckEnabled(struct RuntimeAlgorithm *RuntimeAlgorithm,
TPM_ALG_ID algId, // IN: the algorithm to check
UINT16 keySizeInBits, // IN: size of the key in bits
TPM_ECC_CURVE curveId, // IN: curveId if algId == TPM_ALG_ECC
unsigned int maxStateFormatLevel // IN: maximum stateFormatLevel
);
enum RuntimeAlgorithmType {
RUNTIME_ALGO_IMPLEMENTED,
RUNTIME_ALGO_ENABLED,
RUNTIME_ALGO_DISABLED,
RUNTIME_ALGO_CAN_BE_DISABLED,
RUNTIME_ALGO_NUM, /* keep last */
};
char *
RuntimeAlgorithmPrint(struct RuntimeAlgorithm *RuntimeAlgorithm,
enum RuntimeAlgorithmType rat);
#endif /* RUNTIME_ALGORITHM_H */