private void InitTpmParams()

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()