in Tpm2Tester/TestSubstrate/TestFramework.cs [744:1108]
private void InitTpmParams(Tpm2 tpm)
{
if (TpmCfg.ImplementedAlgs != null)
return;
if (TestCfg.Verbose || TestCfg.DumpTpmInfo)
WriteToLog("TPM configuration:");
TpmCfg.Hierarchies = TpmCfg.PlatformDisabled
? new TpmRh[] {TpmRh.Owner, TpmRh.Endorsement}
: new TpmRh[] {TpmRh.Owner, TpmRh.Endorsement, TpmRh.Platform};
// Enumerate commands implemented by the target TPM instance.
// If a test attempts to execute not implemented command, it will be reported
// as "aborted" instead of "failed".
uint totalCommands = Tpm2.GetProperty(MainTpm, Pt.TotalCommands);
TpmCfg.FipsMode = (Tpm2.GetProperty(tpm, Pt.Modes) & (uint)ModesAttr.Fips1402) != 0;
if (TpmCfg.FipsMode)
WriteToLog("FIPS 140-2 compliant");
ICapabilitiesUnion caps;
byte more = tpm.GetCapability(Cap.Commands, (uint)TpmCc.First,
totalCommands, out caps);
TpmCfg.SupportedCommands = Globs.ConvertAll((caps as CcaArray).commandAttributes,
cmdAttr => (TpmCc)(cmdAttr & (CcAttr.commandIndexBitMask | CcAttr.V)))
.ToArray();
Substrate.Assert(totalCommands == TpmCfg.SupportedCommands.Length);
TpmCfg.ResettablePcrs = Tpm2.GetPcrProperty(tpm, PtPcr.ResetL0);
TpmCfg.ExtendablePcrs = Tpm2.GetPcrProperty(tpm, PtPcr.ExtendL0);
TpmCfg.ContextHashAlg = (TpmAlgId)Tpm2.GetProperty(tpm, Pt.ContextHash);
ushort ctxDigestSize = TpmHash.DigestSize(TpmCfg.ContextHashAlg);
var hashAlgs = new List<TpmAlgId>();
var symAlgs = new List<TpmAlgId>();
var blockModes = new List<TpmAlgId>();
more = tpm.GetCapability(Cap.Algs, (uint)TpmAlgId.First,
(uint)TpmAlgId.Last - (uint)TpmAlgId.First + 1,
out caps);
TpmCfg.ImplementedAlgs = Globs.ConvertAll(
(caps as AlgPropertyArray).algProperties,
algProp =>
{
if (algProp.algProperties == AlgorithmAttr.Hash)
{
if (CryptoLib.IsHashAlgorithm(algProp.alg))
{
hashAlgs.Add(algProp.alg);
if (TpmHash.DigestSize(algProp.alg) > ctxDigestSize)
{
WriteErrorToLog("Warning: {0} has larger digest " +
"than that of the context integrity {1}",
algProp.alg, TpmCfg.ContextHashAlg, ConsoleColor.Cyan);
}
}
else
{
WriteErrorToLog("Warning: Tpm2Tester's software crypto " +
"layer does not support {0}",
algProp.alg, ConsoleColor.Cyan);
}
}
else if (algProp.algProperties.HasFlag(AlgorithmAttr.Symmetric))
{
if (algProp.algProperties.HasFlag(AlgorithmAttr.Encrypting))
{
blockModes.Add(algProp.alg);
}
else
{
symAlgs.Add(algProp.alg);
}
}
return algProp.alg;
})
.ToArray();
TpmCfg.HashAlgs = hashAlgs.ToArray();
TpmCfg.HashAlgsEx = Array.CreateInstance(typeof(TpmAlgId), TpmCfg.HashAlgs.Length + 1)
as TpmAlgId[];
TpmCfg.HashAlgsEx[0] = TpmAlgId.Null;
Array.Copy(TpmCfg.HashAlgs, 0, TpmCfg.HashAlgsEx, 1, TpmCfg.HashAlgs.Length);
LogListOfValues("Hash algorithms: ", hashAlgs);
TpmCfg.EccCurves = new Dictionary<EccCurve, AlgorithmDetailEcc>();
var swEccCurves = new List<EccCurve>();
int maxEccKeyBits = 0;
more = tpm._AllowErrors()
.GetCapability(Cap.EccCurves, (uint)0, (uint)0xFFFF, out caps);
if (MainTpm._LastCommandSucceeded())
{
foreach (var curve in (caps as EccCurveArray).eccCurves)
{
AlgorithmDetailEcc curveDetail = tpm.EccParameters(curve);
maxEccKeyBits = Math.Max(maxEccKeyBits, curveDetail.keySize);
var coordBytes = curveDetail.gX.Length;
if (!TpmCfg.Tpm_115_Errata_13() && coordBytes > 32)
{
continue;
}
TpmCfg.EccCurves.Add(curve, curveDetail);
if (AsymCryptoSystem.IsCurveSupported(curve))
{
swEccCurves.Add(curve);
}
}
}
else
{
TestCfg.DisabledTests.Category |= Category.Ecc;
}
LogListOfValues("ECC curves: ", TpmCfg.EccCurves.Keys);
TpmCfg.SwEccCurves = swEccCurves.ToArray();
TpmCfg.MaxEccKeySize = (maxEccKeyBits + 7) / 8;
TpmCfg.MaxDigestSize = (ushort)Tpm2.GetProperty(MainTpm, Pt.MaxDigest);
TpmCfg.MaxInputBuffer = (ushort)Tpm2.GetProperty(tpm, Pt.InputBuffer);
TpmCfg.MaxNvIndexSize = (ushort)Tpm2.GetProperty(tpm, Pt.NvIndexMax);
TpmCfg.MaxNvOpSize = (ushort)Tpm2.GetProperty(tpm, Pt.NvBufferMax);
TpmCfg.MaxLabelSize = Math.Min(32, (Math.Min(TpmCfg.MaxEccKeySize, TpmCfg.MaxDigestSize)));
// Some TPMs allow NV index to take most of the NV. This would break some
// tests. Thus, force the decreased limit.
TpmHandle nvHandle1 = TpmHandle.NV(TestConfig.MaxNvIndex + 1);
TpmHandle nvHandle2 = TpmHandle.NV(TestConfig.MaxNvIndex + 2);
while (true)
{
var nvPub = new NvPublic(nvHandle1, TpmCfg.HashAlgs[0], TestConfig.DefaultNvAttrs,
null, TpmCfg.MaxNvIndexSize);
tpm._ExpectResponses(TpmRc.Success, TpmRc.NvSpace, TpmRc.BadAuth, TpmRc.NvDefined)
.NvDefineSpace(TpmRh.Owner, null, nvPub);
if (tpm._GetLastResponseCode() == TpmRc.NvDefined)
{
nvHandle1.handle++;
nvHandle2.handle++;
continue;
}
// OwnerAuth value recovery
// NOTE: Similar code is used by CleanNv(). Update in sync.
if (tpm._GetLastResponseCode() == TpmRc.BadAuth)
{
// Owner auth may have been changed by a previously failed test
tpm[TestConfig.TempAuth]._ExpectResponses(TpmRc.Success, TpmRc.NvSpace, TpmRc.BadAuth)
.NvDefineSpace(TpmRh.Owner, null, nvPub);
if (tpm._LastCommandSucceeded())
{
tpm.OwnerAuth = TestConfig.TempAuth;
}
else if (!Globs.IsZeroBuffer(tpm.OwnerAuth))
{
tpm[NullAuth]._ExpectResponses(TpmRc.Success, TpmRc.NvSpace)
.NvDefineSpace(TpmRh.Owner, null, nvPub);
if (tpm._LastCommandSucceeded())
{
tpm.OwnerAuth = NullAuth;
}
}
}
if (tpm._LastCommandSucceeded())
{
nvPub.nvIndex = nvHandle2;
tpm._ExpectResponses(TpmRc.Success, TpmRc.NvSpace)
.NvDefineSpace(TpmRh.Owner, null, nvPub);
bool secondIndexAllocated = tpm._LastCommandSucceeded();
tpm.NvUndefineSpace(TpmRh.Owner, nvHandle1);
if (secondIndexAllocated)
{
tpm.NvUndefineSpace(TpmRh.Owner, nvHandle2);
break;
}
}
if (TpmCfg.MaxNvIndexSize / 2 < 2048)
{
TpmCfg.MaxNvIndexSize = 2048;
break;
}
else
TpmCfg.MaxNvIndexSize /= 2;
}
// Workaround for TPMs incorrectly reporting TPM_PT_NV_BUFFER_MAX property
if (TpmCfg.MaxNvOpSize == 0)
{
TpmCfg.MaxNvOpSize = TpmCfg.MaxDigestSize;
}
TpmCfg.SafeNvIndexSize = Math.Min(TpmCfg.MaxNvIndexSize, TpmCfg.MaxNvOpSize);
PcrSelection.MaxPcrs = (ushort)Tpm2.GetProperty(tpm, Pt.PcrCount);
TpmCfg.MaxQualDataSize = (ushort)(TpmCfg.MaxDigestSize + sizeof(UInt16));
TpmCfg.LargestHashAlg = TpmCfg.ShortestHashAlg = TpmAlgId.None;
TpmCfg.MinDigestSize = ushort.MaxValue;
TpmCfg.MaxDigestSize = 0;
foreach (var alg in TpmCfg.HashAlgs)
{
var digestSize = TpmHash.DigestSize(alg);
if (TpmCfg.MaxDigestSize < digestSize)
{
TpmCfg.MaxDigestSize = digestSize;
TpmCfg.LargestHashAlg = alg;
}
if (TpmCfg.MinDigestSize > digestSize)
{
TpmCfg.ShortestHashAlg = alg;
TpmCfg.MinDigestSize = digestSize;
}
}
var keySizes = new List<ushort>();
var symDef = new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb);
var rsaParms = new RsaParms(symDef, null, 1024, 0);
IPublicParmsUnion parms = null;
if (TpmCfg.IsImplemented(TpmAlgId.Rsa))
{
// Find the smallest supported RSA size (currently checks only 1024 and 2048)
tpm._AllowErrors().TestParms(rsaParms);
if (!tpm._LastCommandSucceeded())
{
rsaParms.keyBits = 2048;
tpm._AllowErrors().TestParms(rsaParms);
if (!tpm._LastCommandSucceeded())
{
symDef.KeyBits = 256;
tpm._AllowErrors().TestParms(rsaParms);
if (!tpm._LastCommandSucceeded())
{
WriteToLog("WARNING: Unrecognized TPM algorithm configuration.\n" +
" No standard RSA/AES combinations found.\n" +
" Attempting to continue...", ConsoleColor.Cyan);
}
}
}
parms = rsaParms;
}
else
{
var curve = TpmCfg.IsImplemented(EccCurve.NistP256) ? EccCurve.NistP256 : TpmCfg.EccCurves.Keys.First();
parms = new EccParms(symDef, null, curve, new NullKdfScheme());
tpm._AllowErrors().TestParms(parms);
if (!tpm._LastCommandSucceeded())
{
symDef.KeyBits = 256;
parms = new EccParms(symDef, null, curve, new NullKdfScheme());
tpm._AllowErrors().TestParms(parms);
if (!tpm._LastCommandSucceeded())
{
WriteToLog("WARNING: Unrecognized TPM algorithm configuration.\n" +
" No RSA is supported and, no working ECC/AES combination found.\n" +
" Attempting to continue...", ConsoleColor.Cyan);
}
}
}
var allModes = new TpmAlgId[] { TpmAlgId.Cfb, TpmAlgId.Ctr,
TpmAlgId.Ofb, TpmAlgId.Cbc, TpmAlgId.Ecb };
var modes = new HashSet<TpmAlgId>();
var symDefs = new List<SymDefObject>();
var swSymDefs = new List<SymDefObject>();
foreach (var alg in symAlgs)
{
if (alg == TpmAlgId.Xor)
continue;
symDef.Algorithm = alg;
for (ushort n = symDef.KeyBits; n <= 256; n += 64)
{
symDef.KeyBits = n;
foreach (TpmAlgId mode in allModes)
{
symDef.Mode = mode;
tpm._AllowErrors().TestParms(parms);
if (tpm._LastCommandSucceeded())
{
if (mode == TpmAlgId.Cfb)
{
keySizes.Add(n);
}
var sd = symDef.Copy();
symDefs.Add(sd);
modes.Add(sd.Mode);
using (var sym = SymCipher.Create(sd))
{
if (sym != null && !sym.LimitedSupport)
{
swSymDefs.Add(sd);
}
}
}
}
}
if (alg == TpmAlgId.Aes)
{
TpmCfg.AesKeySizes = keySizes.ToArray();
}
else if (alg == TpmAlgId.Tdes)
{
TpmCfg.DesKeySizes = keySizes.ToArray();
}
LogKeyParams(alg, keySizes);
keySizes.Clear();
}
TpmCfg.SymDefs = symDefs.ToArray();
TpmCfg.CfbSymDefs = TpmCfg.SymDefs.Where(sd => sd.Mode == TpmAlgId.Cfb).ToArray();
TpmCfg.SwSymDefs = swSymDefs.ToArray();
TpmCfg.SwCfbSymDefs = TpmCfg.SwSymDefs.Where(sd => sd.Mode == TpmAlgId.Cfb).ToArray();
TpmCfg.SymModes = modes.ToArray();
LogListOfValues("Block cipher modes: ", modes);
if (TpmCfg.IsImplemented(TpmAlgId.Rsa))
{
rsaParms.symmetric = TpmCfg.SymDefs[0];
for (ushort n = rsaParms.keyBits; n <= 4096; n += 1024)
{
rsaParms.keyBits = n;
tpm._AllowErrors().TestParms(rsaParms);
if (tpm._LastCommandSucceeded())
{
keySizes.Add(n);
}
}
LogKeyParams(TpmAlgId.Rsa, keySizes);
}
TpmCfg.RsaKeySizes = keySizes.ToArray();
#if false
// Test Tpm2Tester correctness in case not all PCR banks are allocated
var allocatedPcrs = new uint[PcrSelection.MaxPcrs];
for (uint i = 0; i < PcrSelection.MaxPcrs; ++i)
{
allocatedPcrs[i] = i;
}
var pcrBanks = new PcrSelection[TpmCfg.HashAlgs.Length];
for (int i = 0; i < TpmCfg.HashAlgs.Length; ++i)
{
pcrBanks[i] = new PcrSelection(TpmCfg.HashAlgs[i],
TpmCfg.HashAlgs[i] != TpmAlgId.Sha256 ? allocatedPcrs : new uint[0]);
}
uint maxNum, sizeNeeded, sizeAvailable;
uint success = tpm.PcrAllocate(TpmRh.Platform, pcrBanks, out maxNum,
out sizeNeeded, out sizeAvailable);
Substrate.Assert(success == 1 && tpm._LastCommandSucceeded());
RecoveryResetTpm(tpm);
#endif
more = tpm.GetCapability(Cap.Pcrs, 0, 64, out caps);
Substrate.Assert(more == 0);
PcrSelectionArray sa = caps as PcrSelectionArray;
foreach (var sel in sa.pcrSelections)
{
if (sel.NumPcrsSelected() > 0)
{
TpmCfg.PcrBanks.Add(sel);
}
}
} // InitTpmParams()