示例#1
0
文件: TpmKey.cs 项目: jimsdog/TSS.MSR
        /// <summary>
        // Calculate and return the name of the entity. The name is an alg-prepended
        // digest in a byte buffer
        /// </summary>
        /// <returns></returns>
        public byte[] GetName()
        {
            byte[]  rawData   = GetTpmRepresentation();
            TpmHash pubDigest = TpmHash.FromData(nameAlg, rawData);

            return(Marshaller.GetTpmRepresentation(pubDigest));
        }
示例#2
0
 /// <summary>
 /// Composes and returns a valid TPM response buffer containg the given
 /// error response code.
 /// </summary>
 /// <param name="errorCode"></param>
 /// <returns></returns>
 public static byte[] BuildErrorResponseBuffer(TpmRc errorCode)
 {
     return(Marshaller.GetTpmRepresentation(new Object[] {
         TpmSt.NoSessions,
         (uint)10,
         errorCode
     }));
 }
示例#3
0
        /// <summary>
        /// Make a new TpmHash from the hash of the TPM representation of data
        /// </summary>
        /// <param name="hashAlg"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public static TpmHash FromObject(TpmAlgId hashAlg, Object data)
        {
            var newHash = new TpmHash(hashAlg);

            byte[] temp = Marshaller.GetTpmRepresentation(data);
            newHash.HashData = CryptoLib.HashData(hashAlg, temp);
            return(newHash);
        }
示例#4
0
        } // VerifySignature()

        /// <summary>
        /// Generates the key exchange key and the public part of the ephemeral key
        /// using specified encoding parameters in the KDF (ECC only).
        /// </summary>
        /// <param name="encodingParms"></param>
        /// <param name="decryptKeyNameAlg"></param>
        /// <param name="ephemPub"></param>
        /// <returns>key exchange key blob</returns>
        public byte[] EcdhGetKeyExchangeKey(byte[] encodingParms, TpmAlgId decryptKeyNameAlg, out EccPoint ephemPub)
        {
            byte[] keyExchangeKey = null;
            ephemPub = null;

#if !__MonoCS__
            var eccParms = (EccParms)PublicParms.parameters;
            int keyBits  = RawEccKey.GetKeyLength(eccParms.curveID);

            // Make a new ephemeral key
#if TSS_USE_BCRYPT
            var    ephKey   = Generate(RawEccKey.GetEccAlg(PublicParms), (uint)keyBits);
            byte[] ephPub   = ephKey.Export(Native.BCRYPT_ECCPUBLIC_BLOB);
            byte[] otherPub = Key.Export(Native.BCRYPT_ECCPUBLIC_BLOB);
#else
            using (var eph = new ECDiffieHellmanCng(keyBits))
            {
                byte[] otherPub = EcDhProvider.PublicKey.ToByteArray();
                byte[] ephPub   = eph.PublicKey.ToByteArray();

                eph.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
                eph.HashAlgorithm         = GetCngAlgorithm(decryptKeyNameAlg);
#endif // !TSS_USE_BCRYPT

            byte[] herPubX, herPubY;
            RawEccKey.KeyInfoFromPublicBlob(otherPub, out herPubX, out herPubY);

            byte[] myPubX, myPubY;
            RawEccKey.KeyInfoFromPublicBlob(ephPub, out myPubX, out myPubY);

            byte[] otherInfo = Globs.Concatenate(new[] { encodingParms, myPubX, herPubX });

            // The TPM uses the following number of bytes from the KDF
            int bytesNeeded = CryptoLib.DigestSize(decryptKeyNameAlg);
            keyExchangeKey = new byte[bytesNeeded];

            for (int pos = 0, count = 1, bytesToCopy = 0;
                 pos < bytesNeeded;
                 ++count, pos += bytesToCopy)
            {
                byte[] secretPrepend = Marshaller.GetTpmRepresentation((UInt32)count);
#if TSS_USE_BCRYPT
                byte[] fragment = ephKey.DeriveKey(Key, decryptKeyNameAlg, secretPrepend, otherInfo);
#else
                eph.SecretAppend  = otherInfo;
                eph.SecretPrepend = secretPrepend;
                byte[] fragment = eph.DeriveKeyMaterial(EcDhProvider.Key);
#endif // !TSS_USE_BCRYPT
                bytesToCopy = Math.Min(bytesNeeded - pos, fragment.Length);
                Array.Copy(fragment, 0, keyExchangeKey, pos, bytesToCopy);
            }
            ephemPub = new EccPoint(myPubX, myPubY);
#if !TSS_USE_BCRYPT
        }
#endif
#endif // !__MonoCS__
            return(keyExchangeKey);
        }
示例#5
0
        /// <summary>
        /// Create activation blobs that can be passed to ActivateCredential.  Two blobs are returned -
        /// (a) - encryptedSecret - is the symmetric key cfb-symmetrically encrypted with an enveloping key
        /// (b) credentialBlob (the return value of this function) - is the enveloping key OEAP (RSA) encrypted
        ///         by the public part of this key.
        /// </summary>
        /// <param name="secret"></param>
        /// <param name="nameAlgId"></param>
        /// <param name="nameOfKeyToBeActivated"></param>
        /// <param name="encryptedSecret"></param>
        /// <returns>CredentialBlob (</returns>
        public byte[] CreateActivationCredentials(
            byte[] secret,
            TpmAlgId nameAlgId,
            byte[] nameOfKeyToBeActivated,
            out byte[] encryptedSecret)
        {
            byte[] seed, encSecret;

            switch (type)
            {
            case TpmAlgId.Rsa:
                // The seed should be the same size as the symmKey
                seed      = Globs.GetRandomBytes((CryptoLib.DigestSize(nameAlg) + 7) / 8);
                encSecret = EncryptOaep(seed, ActivateEncodingParms);
                break;

            case TpmAlgId.Ecc:
                EccPoint pubEphem;
                seed      = EcdhGetKeyExchangeKey(ActivateEncodingParms, nameAlg, out pubEphem);
                encSecret = Marshaller.GetTpmRepresentation(pubEphem);
                break;

            default:
                Globs.Throw <NotImplementedException>("CreateActivationCredentials: Unsupported algorithm");
                encryptedSecret = new byte[0];
                return(new byte[0]);
            }

            var cvx = new Tpm2bDigest(secret);

            byte[] cvTpm2B = Marshaller.GetTpmRepresentation(cvx);

            SymDefObject symDef = TssObject.GetSymDef(this);

            byte[] symKey = KDF.KDFa(nameAlg, seed, "STORAGE", nameOfKeyToBeActivated, new byte[0], symDef.KeyBits);

            byte[] encIdentity;
            using (SymmCipher symm2 = SymmCipher.Create(symDef, symKey))
            {
                encIdentity = symm2.Encrypt(cvTpm2B);
            }

            var hmacKeyBits = CryptoLib.DigestSize(nameAlg);

            byte[] hmacKey   = KDF.KDFa(nameAlg, seed, "INTEGRITY", new byte[0], new byte[0], hmacKeyBits * 8);
            byte[] outerHmac = CryptoLib.HmacData(nameAlg,
                                                  hmacKey,
                                                  Globs.Concatenate(encIdentity, nameOfKeyToBeActivated));

            byte[] activationBlob = Globs.Concatenate(
                Marshaller.ToTpm2B(outerHmac),
                encIdentity);
            encryptedSecret = encSecret;

            return(activationBlob);
        }
示例#6
0
 private void ProcessError(string message, out byte[] byteBuf)
 {
     Console.Error.WriteLine(message);
     Console.Error.WriteLine("This will be processed as a TpmRc.NotUsed error");
     byteBuf = Marshaller.GetTpmRepresentation(new Object[] {
         TpmSt.NoSessions,
         (uint)10,
         TpmRc.NotUsed
     });
 }
示例#7
0
        /// <summary>
        /// Get the date of the specification from which the TPM was built.
        /// </summary>
        /// <param name="manufacturer"></param>
        /// <param name="year"></param>
        /// <param name="dayOfYear"></param>
        /// <param name="tpm"></param>
        public static void GetTpmInfo(Tpm2 tpm, out string manufacturer, out uint year, out uint dayOfYear)
        {
            // ReSharper disable once RedundantAssignment
            manufacturer = "";
            year         = GetProperty(tpm, Pt.Year);
            dayOfYear    = GetProperty(tpm, Pt.DayOfYear);

            uint manX = GetProperty(tpm, Pt.Manufacturer);
            var  arr  = Marshaller.GetTpmRepresentation(manX);

            manufacturer = (new System.Text.UTF8Encoding()).GetString(arr, 0, arr.Length);
        }
示例#8
0
 /// <summary>
 /// Calculate the qualified name of an object presumed loaded under the provided ancestral chain
 /// in a given hierarchy.
 /// </summary>
 /// <param name="hierarchyHandle"></param>
 /// <param name="children"></param>
 /// <returns></returns>
 public static byte[] GetQualifiedName(TpmHandle hierarchyHandle, TpmPublic[] children)
 {
     byte[] runningName = Marshaller.GetTpmRepresentation(hierarchyHandle);
     foreach (TpmPublic pub in children)
     {
         byte[] thisName = pub.GetName();
         runningName = Globs.Concatenate
                       (
             Marshaller.GetTpmRepresentation(pub.nameAlg),
             CryptoLib.HashData(pub.nameAlg, new[] { runningName, thisName })
                       );
     }
     return(runningName);
 }
示例#9
0
        /// <summary>
        /// Create an enveloped (encrypted and integrity protected) private area from a provided sensitive.
        /// </summary>
        /// <param name="iv"></param>
        /// <param name="sens"></param>
        /// <param name="nameHash"></param>
        /// <param name="publicName"></param>
        /// <param name="symWrappingAlg"></param>
        /// <param name="symKey"></param>
        /// <param name="parentNameAlg"></param>
        /// <param name="parentSeed"></param>
        /// <param name="f"></param>
        /// <returns></returns>
        public static byte[] CreatePrivateFromSensitive(
            SymDefObject symWrappingAlg,
            byte[] symKey,
            byte[] iv,
            Sensitive sens,
            TpmAlgId nameHash,
            byte[] publicName,
            TpmAlgId parentNameAlg,
            byte[] parentSeed,
            TssObject.Transformer f = null)
        {
            // ReSharper disable once InconsistentNaming
            byte[] tpm2bIv = Marshaller.ToTpm2B(iv);
            Transform(tpm2bIv, f);

            byte[] sensitive = sens.GetTpmRepresentation();
            Transform(sensitive, f);

            // ReSharper disable once InconsistentNaming
            byte[] tpm2bSensitive = Marshaller.ToTpm2B(sensitive);
            Transform(tpm2bSensitive, f);

            byte[] encSensitive = SymCipher.Encrypt(symWrappingAlg, symKey, iv, tpm2bSensitive);
            Transform(encSensitive, f);
            byte[] decSensitive = SymCipher.Decrypt(symWrappingAlg, symKey, iv, encSensitive);
            Debug.Assert(f != null || Globs.ArraysAreEqual(decSensitive, tpm2bSensitive));

            var hmacKeyBits = CryptoLib.DigestSize(parentNameAlg) * 8;

            byte[] hmacKey = KDF.KDFa(parentNameAlg, parentSeed, "INTEGRITY", new byte[0], new byte[0], hmacKeyBits);
            Transform(hmacKey, f);

            byte[] dataToHmac = Marshaller.GetTpmRepresentation(tpm2bIv,
                                                                encSensitive,
                                                                publicName);
            Transform(dataToHmac, f);

            byte[] outerHmac = CryptoLib.Hmac(parentNameAlg, hmacKey, dataToHmac);
            Transform(outerHmac, f);

            byte[] priv = Marshaller.GetTpmRepresentation(Marshaller.ToTpm2B(outerHmac),
                                                          tpm2bIv,
                                                          encSensitive);
            Transform(priv, f);
            return(priv);
        }
示例#10
0
        /// <summary>
        /// Calculate and return the auth-hmac (or plaintext auth if it is a policy session with PlaintextAuth set)
        /// based on the current session parms.
        /// </summary>
        /// <param name="parmHash"></param>
        /// <param name="direction"></param>
        /// <param name="nonceDec"></param>
        /// <param name="nonceEnc"></param>
        /// <returns></returns>
        internal byte[] GetAuthHmac(byte[] parmHash, Direction direction, byte[] nonceDec = null, byte[] nonceEnc = null)
        {
            // special case.  If this is a policy session and the session includes PolicyPassword the
            // TPM expects and assumes that the HMAC field will have the plaintext entity field as in
            // a PWAP session (the related PolicyAuthValue demands an HMAC as usual)
            if (PlaintextAuth)
            {
                return(Handle.Auth ?? AuthHandle.Auth);
            }

            byte[] nonceNewer, nonceOlder;
            if (direction == Direction.Command)
            {
                nonceNewer = NonceCaller;
                nonceOlder = NonceTpm;
            }
            else
            {
                nonceNewer = NonceTpm;
                nonceOlder = NonceCaller;
            }
            byte[] sessionAttrs = Marshaller.GetTpmRepresentation(Attrs);

            byte[] auth = Handle.Auth;
            if (AuthHandle != null && Handle != TpmRh.TpmRsPw && auth == null &&
                ((SessionType != TpmSe.Policy && BindObject != AuthHandle) ||
                 (SessionType == TpmSe.Policy && SessIncludesAuth)))
            {
                auth = Globs.TrimTrailingZeros(AuthHandle.Auth);
            }
            byte[] hmacKey   = Globs.Concatenate(SessionKey, auth);
            byte[] bufToHmac = Globs.Concatenate(new[] { parmHash, nonceNewer, nonceOlder,
                                                         nonceDec, nonceEnc, sessionAttrs });

            byte[] hmac = CryptoLib.Hmac(AuthHash, hmacKey, bufToHmac);
#if false
            Console.WriteLine(Globs.FormatBytesCompact("hmacKey: ", hmacKey));
            Console.WriteLine(Globs.FormatBytesCompact("nonceNewer: ", nonceNewer));
            Console.WriteLine(Globs.FormatBytesCompact("nonceOlder: ", nonceOlder));
            Console.WriteLine(Globs.FormatBytesCompact("nonceDec: ", nonceDec));
            Console.WriteLine(Globs.FormatBytesCompact("nonceEnc: ", nonceEnc));
            Console.WriteLine(Globs.FormatBytesCompact("attrs: ", sessionAttrs));
            Console.WriteLine(Globs.FormatBytesCompact("HMAC: ", hmac));
#endif
            return(hmac);
        }
示例#11
0
        /// <summary>
        /// Get the TPM name of the associated entity.
        ///
        /// If the entity is a transient object, persistent object or NV index, the
        /// name must have been previously set explicitly by the caller (by means of
        /// SetName() or GetName(Tpm2 tpm) methods) or implicitly by the framework
        /// (when an object is created by means of CreatePrimary, CreateLoaded or
        /// Create command).
        ///
        /// Otherwise the name is a 4-byte TPM representation of the handle value.
        /// </summary>
        public byte[] GetName()
        {
            Ht ht = GetType();

            switch (ht)
            {
            case Ht.Transient:
            case Ht.Persistent:
            case Ht.NvIndex:
                return(_Name);

            case Ht.Pcr:
            case Ht.HmacSession:
            case Ht.PolicySession:
            case Ht.Permanent:
                return(Marshaller.GetTpmRepresentation(handle));

            default:
                return(null);
            }
        }
示例#12
0
        /// <summary>
        /// Implements marshaling logic for most of the TPM object types.
        /// Can be overridden if a custom marshaling logic is required (e.g. when
        /// marshaling of a field depends on other field's value).
        /// </summary>
        /// <param name="m"></param>
        /// <returns></returns>
        internal virtual void ToNet(Marshaller m)
        {
            var members = GetFieldsToMarshal();

            dbg.Indent();
            for (int i = 0; i < members.Length; ++i)
            {
                var    mem    = members[i];
                object memVal = Globs.GetMember(mem, this);
                dbg.Trace(i + ": " + mem.Name + " = " + memVal);
                if (mem.SizeLength > 0)
                {
                    bool arr = mem.WireType == MarshalType.VariableLengthArray;
                    int  len = arr ? (memVal == null ? 0 : ((Array)memVal).Length)
                                  : Marshaller.GetTpmRepresentation(memVal).Length;
                    dbg.Trace("Sending " + (arr ? "Array " : "Struct ") + mem.Name + " of size " + len);
                    m.PutSizeTag(len, mem.SizeLength, mem.SizeName);
                }
                m.Put(memVal, mem.Name);
            }
            dbg.Unindent();
        }
        /// <summary>
        /// Create an enveloped (encrypted and integrity protected) private area from a provided sensitive.
        /// </summary>
        /// <param name="iv"></param>
        /// <param name="sens"></param>
        /// <param name="nameHash"></param>
        /// <param name="publicName"></param>
        /// <param name="symWrappingAlg"></param>
        /// <param name="symKey"></param>
        /// <param name="parentNameAlg"></param>
        /// <param name="parentSeed"></param>
        /// <param name="f"></param>
        /// <returns></returns>
        public static byte[] CreatePrivateFromSensitive(
            SymDefObject symWrappingAlg,
            byte[] symKey,
            byte[] iv,
            Sensitive sens,
            TpmAlgId nameHash,
            byte[] publicName,
            TpmAlgId parentNameAlg,
            byte[] parentSeed)
        {
            // ReSharper disable once InconsistentNaming
            byte[] tpm2bIv = Marshaller.ToTpm2B(iv);

            byte[] sensitive = sens.GetTpmRepresentation();

            // ReSharper disable once InconsistentNaming
            byte[] tpm2bSensitive = Marshaller.ToTpm2B(sensitive);

            byte[] encSensitive = SymmCipher.Encrypt(symWrappingAlg, symKey, iv, tpm2bSensitive);
            byte[] decSensitive = SymmCipher.Decrypt(symWrappingAlg, symKey, iv, encSensitive);

            var hmacKeyBits = CryptoLib.DigestSize(parentNameAlg) * 8;

            byte[] hmacKey = KDF.KDFa(parentNameAlg, parentSeed, "INTEGRITY", new byte[0], new byte[0], hmacKeyBits);

            byte[] dataToHmac = Marshaller.GetTpmRepresentation(tpm2bIv,
                                                                encSensitive,
                                                                publicName);

            byte[] outerHmac = CryptoLib.HmacData(parentNameAlg, hmacKey, dataToHmac);

            byte[] priv = Marshaller.GetTpmRepresentation(Marshaller.ToTpm2B(outerHmac),
                                                          tpm2bIv,
                                                          encSensitive);
            return(priv);
        }
示例#14
0
 /// <summary>
 /// Replace the hash value with the hash of the concatenation of the current value and the TPM representation
 /// of objectToExtend
 /// </summary>
 /// <param name="objectToExtend"></param>
 /// <returns></returns>
 public TpmHash Extend(Object objectToExtend)
 {
     byte[] temp = Marshaller.GetTpmRepresentation(objectToExtend);
     HashData = CryptoLib.HashData(HashAlg, HashData, temp);
     return(this);
 }
示例#15
0
        internal virtual void ToHost(Marshaller m)
        {
            var members = GetFieldsToMarshal(true);

            dbg.Indent();
            for (int i = 0; i < members.Length; ++i)
            {
                TpmStructMemberInfo memInfo = members[i];
                Type memType = Globs.GetMemberType(memInfo);
                var  wt      = members[i].WireType;
                switch (wt)
                {
                case MarshalType.Union:
                {
                    dbg.Trace("Union " + memType.Name + " with selector " + memInfo.Tag.Value);
                    memInfo.Value = m.Get(UnionElementFromSelector(memType, memInfo.Tag.Value), memType.Name);
                    break;
                }

                case MarshalType.FixedLengthArray:
                {
                    object arr = Globs.GetMember(memInfo, this);
                    memInfo.Value = m.GetArray(memType.GetElementType(), (arr as Array).Length, memInfo.Name);
                    break;
                }

                case MarshalType.VariableLengthArray:
                {
                    int size = m.GetSizeTag(memInfo.SizeLength, memInfo.SizeName);
                    memInfo.Value = m.GetArray(memType.GetElementType(), size, memInfo.Name);
                    Debug.Assert(size == ((Array)memInfo.Value).Length);
                    dbg.Trace("Received Array " + memInfo.Name + " of size " + size);
                    break;
                }

                case MarshalType.SizedStruct:
                {
                    int size = m.GetSizeTag(memInfo.SizeLength, memInfo.SizeName);
                    if (size != 0)
                    {
                        memInfo.Value = m.Get(memType, memInfo.Name);
                        Debug.Assert(size == Marshaller.GetTpmRepresentation(memInfo.Value).Length);
                    }
                    dbg.Trace("Received Struct " + memInfo.Name + " of size " + size);
                    break;
                }

                default:
                    // Only attempt unmarshaling a field, if it is not sized or
                    // if its size is non-zero.
                    if (memInfo.Tag == null ||
                        memInfo.Tag.GetValueAsUInt() != 0)
                    {
                        memInfo.Value = m.Get(memType, memInfo.Name);
                    }
                    break;
                }
                dbg.Trace((i + 1) + ": " + memInfo.Name + " = " + memInfo.Value);
                // Some property values are dynamically obtained from their linked fields.
                // Correspondingly, they do not have a setter, so we bypass them here.
                Debug.Assert(wt != MarshalType.LengthOfStruct && wt != MarshalType.ArrayCount);
                if (wt != MarshalType.UnionSelector)
                {
                    Globs.SetMember(memInfo, this, memInfo.Value);
                }
            }
            dbg.Unindent();
        }
示例#16
0
文件: TpmKey.cs 项目: jimsdog/TSS.MSR
        /// <summary>
        /// Creates a duplication blob for the current key that can be Imported as a child
        /// of newParent. Three forms are possible. GetPlaintextDuplicationBlob() allows
        /// plaintext-import. This function enables duplication with and without an
        /// inner wrapper (depending on whether innerWrapper is null)
        /// </summary>
        /// <param name="newParent"></param>
        /// <param name="innerWrapper"></param>
        /// <param name="encSecret"></param>
        /// <returns></returns>
        public TpmPrivate GetDuplicationBlob(
            TpmPublic pubNewParent,
            SymCipher innerWrapper,
            out byte[] encSecret)
        {
            byte[] encSensitive;
            if (innerWrapper == null)
            {
                // No inner wrapper
                encSensitive = Marshaller.ToTpm2B(Sensitive.GetTpmRepresentation());
                Transform(encSensitive);
            }
            else
            {
                byte[] sens   = Marshaller.ToTpm2B(Sensitive.GetTpmRepresentation());
                byte[] toHash = Globs.Concatenate(sens, GetName());
                Transform(toHash);
                byte[] innerIntegrity = Marshaller.ToTpm2B(CryptoLib.HashData(
                                                               Public.nameAlg, toHash));
                byte[] innerData = Globs.Concatenate(innerIntegrity, sens);
                Transform(innerData);
                encSensitive = innerWrapper.Encrypt(innerData);
                Transform(encSensitive);
            }

            byte[]       seed;
            SymDefObject symDef = GetSymDef(pubNewParent).Copy();

            // TPM duplication procedures always use CFB mode
            symDef.Mode = TpmAlgId.Cfb;

            using (var swNewParent = AsymCryptoSystem.CreateFrom(pubNewParent))
            {
                switch (pubNewParent.type)
                {
                case TpmAlgId.Rsa:
                    // The seed should be the same size as the scheme hash
                    LastSeed =
                        seed = Globs.GetRandomBytes(
                            CryptoLib.DigestSize(swNewParent.OaepHash));
                    encSecret = swNewParent.EncryptOaep(seed, DuplicateEncodingParms);
                    break;

                case TpmAlgId.Ecc:
                    EccPoint pubEphem;
                    seed = swNewParent.EcdhGetKeyExchangeKey(DuplicateEncodingParms,
                                                             pubNewParent.nameAlg,
                                                             out pubEphem);
                    encSecret = Marshaller.GetTpmRepresentation(pubEphem);
                    break;

                default:
                    Globs.Throw <NotImplementedException>(
                        "GetDuplicationBlob: Unsupported algorithm");
                    encSecret = new byte[0];
                    return(new TpmPrivate());
                }
            }
            Transform(seed);
            Transform(encSecret);

            byte[] symKey = KDF.KDFa(pubNewParent.nameAlg, seed, "STORAGE",
                                     Public.GetName(), new byte[0], symDef.KeyBits);
            Transform(symKey);

            byte[] dupSensitive;
            using (SymCipher enc2 = SymCipher.Create(symDef, symKey))
            {
                if (enc2 == null)
                {
                    return(null);
                }

                dupSensitive = enc2.Encrypt(encSensitive);
            }
            Transform(dupSensitive);

            var npNameNumBits = CryptoLib.DigestSize(pubNewParent.nameAlg) * 8;

            byte[] hmacKey = KDF.KDFa(pubNewParent.nameAlg, seed, "INTEGRITY",
                                      new byte[0], new byte[0], npNameNumBits);

            byte[] outerDataToHmac = Globs.Concatenate(dupSensitive, Public.GetName());
            Transform(outerDataToHmac);

            byte[] outerHmac = Marshaller.ToTpm2B(CryptoLib.Hmac(pubNewParent.nameAlg,
                                                                 hmacKey, outerDataToHmac));
            Transform(outerHmac);

            byte[] dupBlob = Globs.Concatenate(outerHmac, dupSensitive);
            Transform(dupBlob);

            return(new TpmPrivate(dupBlob));
        }
示例#17
0
文件: TpmKey.cs 项目: jimsdog/TSS.MSR
        /// <summary>
        /// Create activation blobs that can be passed to ActivateCredential. Two
        /// blobs are returned:
        /// 1) encryptedSecret - symmetric key cfb-symmetrically encrypted with the
        ///                      enveloping key;
        /// 2) credentialBlob -  the enveloping key OEAP (RSA) encrypted by the public
        ///                      part of this key. This is the return value of this
        ///                      function
        /// </summary>
        /// <param name="secret"></param>
        /// <param name="nameOfKeyToBeActivated"></param>
        /// <param name="encryptedSecret"></param>
        /// <returns>CredentialBlob (</returns>
        public IdObject CreateActivationCredentials(byte[] secret,
                                                    byte[] nameOfKeyToBeActivated,
                                                    out byte[] encryptedSecret)
        {
            byte[] seed, encSecret;

            switch (type)
            {
            case TpmAlgId.Rsa:
                // The seed should be the same size as the name algorithmdigest
                seed      = Globs.GetRandomBytes(CryptoLib.DigestSize(nameAlg));
                encSecret = EncryptOaep(seed, ActivateEncodingParms);
                break;

            case TpmAlgId.Ecc:
                EccPoint ephemPubPt;
                seed      = EcdhGetKeyExchangeKey(ActivateEncodingParms, out ephemPubPt);
                encSecret = Marshaller.GetTpmRepresentation(ephemPubPt);
                break;

            default:
                Globs.Throw <NotImplementedException>(
                    "CreateActivationCredentials: Unsupported algorithm");
                encryptedSecret = new byte[0];
                return(null);
            }

            Transform(seed);
            Transform(encSecret);

            var cvx = new Tpm2bDigest(secret);

            byte[] cvTpm2B = Marshaller.GetTpmRepresentation(cvx);
            Transform(cvTpm2B);

            SymDefObject symDef = TssObject.GetSymDef(this);

            byte[] symKey = KDF.KDFa(nameAlg, seed, "STORAGE",
                                     nameOfKeyToBeActivated, new byte[0], symDef.KeyBits);
            Transform(symKey);

            byte[] encIdentity;
            // TPM only uses CFB mode in its command implementations
            var sd = symDef.Copy();

            sd.Mode = TpmAlgId.Cfb;
            using (var sym = SymCipher.Create(sd, symKey))
            {
                // Not all keys specs are supported by SW crypto
                if (sym == null)
                {
                    encryptedSecret = null;
                    return(null);
                }
                encIdentity = sym.Encrypt(cvTpm2B);
            }
            Transform(encIdentity);

            var hmacKeyBits = CryptoLib.DigestSize(nameAlg);

            byte[] hmacKey = KDF.KDFa(nameAlg, seed, "INTEGRITY",
                                      new byte[0], new byte[0], hmacKeyBits * 8);
            Transform(hmacKey);
            byte[] outerHmac = CryptoLib.Hmac(nameAlg, hmacKey,
                                              Globs.Concatenate(encIdentity, nameOfKeyToBeActivated));
            Transform(outerHmac);


            encryptedSecret = encSecret;
            return(new IdObject(outerHmac, encIdentity));
        }
        } // VerifySignature()

        /// <summary>
        /// Generates the key exchange key and the public part of the ephemeral key
        /// using specified encoding parameters in the KDF (ECC only).
        /// </summary>
        /// <param name="encodingParms"></param>
        /// <param name="decryptKeyNameAlg"></param>
        /// <param name="ephemPub"></param>
        /// <returns>key exchange key blob</returns>
        public byte[] EcdhGetKeyExchangeKey(byte[] encodingParms, TpmAlgId decryptKeyNameAlg, out EccPoint ephemPub)
        {
            var eccParms = (EccParms)PublicParms.parameters;
            int keyBits  = RawEccKey.GetKeyLength(eccParms.curveID);

            byte[] keyExchangeKey = null;
            ephemPub = new EccPoint();

            // Make a new ephemeral key
            var     prov      = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(RawEccKey.GetEccAlg(PublicParms));
            var     ephKey    = prov.CreateKeyPair((uint)keyBits);
            IBuffer ephPubBuf = ephKey.ExportPublicKey(CryptographicPublicKeyBlobType.BCryptEccFullPublicKey);

            byte[] ephPub;
            CryptographicBuffer.CopyToByteArray(ephPubBuf, out ephPub);

            IBuffer otherPubBuf = Key.ExportPublicKey(CryptographicPublicKeyBlobType.BCryptEccFullPublicKey);

            byte[] otherPub;
            CryptographicBuffer.CopyToByteArray(otherPubBuf, out otherPub);

            byte[] herPubX, herPubY;
            RawEccKey.KeyInfoFromPublicBlob(otherPub, out herPubX, out herPubY);

            byte[] myPubX, myPubY;
            RawEccKey.KeyInfoFromPublicBlob(ephPub, out myPubX, out myPubY);

            byte[] otherInfo = Globs.Concatenate(new[] { encodingParms, myPubX, herPubX });

            // The TPM uses the following number of bytes from the KDF
            int bytesNeeded = CryptoLib.DigestSize(decryptKeyNameAlg);

            keyExchangeKey = new byte[bytesNeeded];

            for (int pos = 0, count = 1, bytesToCopy = 0;
                 pos < bytesNeeded;
                 ++count, pos += bytesToCopy)
            {
                byte[] secretPrepend = Marshaller.GetTpmRepresentation((UInt32)count);
                string algName;
                KeyDerivationParameters deriveParams;
                switch (decryptKeyNameAlg)
                {
                case TpmAlgId.Kdf1Sp800108:
                    algName      = KeyDerivationAlgorithmNames.Sp800108CtrHmacSha256;
                    deriveParams = KeyDerivationParameters.BuildForSP800108(CryptographicBuffer.CreateFromByteArray(secretPrepend), CryptographicBuffer.CreateFromByteArray(otherInfo));
                    break;

                case TpmAlgId.Kdf1Sp80056a:
                    algName      = KeyDerivationAlgorithmNames.Sp80056aConcatSha256;
                    deriveParams = KeyDerivationParameters.BuildForSP80056a(CryptographicBuffer.ConvertStringToBinary(algName, BinaryStringEncoding.Utf8),
                                                                            CryptographicBuffer.ConvertStringToBinary("TPM", BinaryStringEncoding.Utf8),
                                                                            CryptographicBuffer.CreateFromByteArray(secretPrepend),
                                                                            CryptographicBuffer.ConvertStringToBinary("", BinaryStringEncoding.Utf8),
                                                                            CryptographicBuffer.CreateFromByteArray(otherInfo));
                    break;

                case TpmAlgId.Kdf2:
                    algName      = KeyDerivationAlgorithmNames.Pbkdf2Sha256;
                    deriveParams = KeyDerivationParameters.BuildForPbkdf2(CryptographicBuffer.CreateFromByteArray(secretPrepend), 1000);
                    break;

                default:
                    Globs.Throw <ArgumentException>("wrong KDF name");
                    return(null);
                }
                KeyDerivationAlgorithmProvider deriveProv = KeyDerivationAlgorithmProvider.OpenAlgorithm(algName);
                IBuffer keyMaterial = CryptographicEngine.DeriveKeyMaterial(Key, deriveParams, (uint)keyBits);
                byte[]  fragment;
                CryptographicBuffer.CopyToByteArray(keyMaterial, out fragment);
                bytesToCopy = Math.Min(bytesNeeded - pos, fragment.Length);
                Array.Copy(fragment, 0, keyExchangeKey, pos, bytesToCopy);
            }
            ephemPub = new EccPoint(myPubX, myPubY);
            return(keyExchangeKey);
        }
示例#19
0
        /// <summary>
        /// Implements unmarshaling logic for most of the TPM object types.
        /// Can be overridden if a custom unmarshaling logic is required (e.g.
        /// when unmarshaling of a field depends on other field's value).
        /// </summary>
        /// <param name="m"></param>
        /// <returns></returns>
        internal virtual void ToHost(Marshaller m)
        {
            dbg.Indent();
            var  members      = GetFieldsToMarshal(true);
            uint mshlStartPos = m.GetGetPos();

            for (int i = 0; i < members.Length; ++i)
            {
                TpmStructMemberInfo memInfo = members[i];
                Type memType  = Globs.GetMemberType(memInfo);
                var  wireType = memInfo.WireType;
                int  size     = -1;
                switch (wireType)
                {
                case MarshalType.Union:
                {
                    dbg.Trace("Union " + memType.Name +
                              " with selector " + memInfo.Tag.Value);
                    var elt = UnionElementFromSelector(memType, memInfo.Tag.Value);
                    memInfo.Value = m.Get(elt, memType.Name);
                    break;
                }

                case MarshalType.FixedLengthArray:
                {
                    object arr = Globs.GetMember(memInfo, this);
                    memInfo.Value = m.GetArray(memType.GetElementType(),
                                               (arr as Array).Length, memInfo.Name);
                    break;
                }

                case MarshalType.SpecialVariableLengthArray:
                {
                    size = CryptoLib.DigestSize((TpmAlgId)members[i - 1].Value);
                    UnmarshalArray(m, memInfo, memType, size);
                    break;
                }

                case MarshalType.VariableLengthArray:
                {
                    size = m.GetSizeTag(memInfo.SizeLength, memInfo.SizeName);
                    UnmarshalArray(m, memInfo, memType, size);
                    break;
                }

                case MarshalType.EncryptedVariableLengthArray:
                {
                    uint unmarshaled = m.GetGetPos() - mshlStartPos;
                    size = m.SizedStructLen[m.SizedStructLen.Count - 1] - (int)unmarshaled;
                    UnmarshalArray(m, memInfo, memType, size);
                    break;
                }

                case MarshalType.SizedStruct:
                {
                    size = m.GetSizeTag(memInfo.SizeLength, memInfo.SizeName);
                    if (size == 0)
                    {
                        break;
                    }
                    m.SizedStructLen.Add(size);
                    memInfo.Value = m.Get(memType, memInfo.Name);
                    int unmSize = Marshaller.GetTpmRepresentation(memInfo.Value).Length;
                    if (unmSize != size)
                    {
                        if (unmSize < size && memType.Name == "TpmPublic")
                        {
                            var pub     = memInfo.Value as TpmPublic;
                            var label   = Marshaller.GetTpmRepresentation(pub.unique);
                            var context = m.GetArray(typeof(byte), size - unmSize, "")
                                          as byte[];
                            pub.unique = new TpmDerive(label, context);
                        }
                        else
                        {
                            var msg = string.Format("Invalid size {0} (instead of "
                                                    + "{1}) for unmarshaled {2}.{3}",
                                                    unmSize, size, this.GetType(), memInfo.Name);
                            throw new TssException(msg);
                        }
                    }
                    m.SizedStructLen.RemoveAt(m.SizedStructLen.Count - 1);
                    break;
                }

                default:
                    // Only attempt unmarshaling a field, if it is not sized or
                    // if its size is non-zero.
                    if (memInfo.Tag == null ||
                        memInfo.Tag.GetValueAsUInt() != 0)
                    {
                        memInfo.Value = m.Get(memType, memInfo.Name);
                    }
                    break;
                }
                dbg.Trace((i + 1) + ": " + wireType + " " + memInfo.Name +
                          (size != -1 ? " of size " + size : ""));
                // Some property values are dynamically obtained from their linked fields.
                // Correspondingly, they do not have a setter, so we bypass them here.
                Debug.Assert(wireType != MarshalType.LengthOfStruct && wireType != MarshalType.ArrayCount);
                if (wireType != MarshalType.UnionSelector)
                {
                    Globs.SetMember(memInfo, this, memInfo.Value);
                }
            }
            dbg.Unindent();
        }
示例#20
0
        /// <summary>
        /// Dispatch a command to the underlying TPM. This method implements all significant functionality.
        /// DispatchCommand examines the command stream and performs (approximately) the following functions
        /// 1) If the command references a handle (session or transient object) then TBS makes sure that the entity
        ///     is loaded. If it is, then the handle is "translated" to the underlying TPM handle. If it is not, then
        ///     TBS checks to see if it has a saved context for the entity, and if so loads it.
        /// 2) If the command will fill a slot, then TBS ensures that a slot is available. It does this by ContextSaving
        ///     the LRU entity of the proper type (that is not used in this command).
        /// </summary>
        /// <param name="caller"></param>
        /// <param name="active"></param>
        /// <param name="inBuf"></param>
        /// <param name="outBuf"></param>
        /// <exception cref="Exception"></exception>
        internal void DispatchCommand(TbsContext caller, CommandModifier active, byte[] inBuf, out byte[] outBuf)
        {
            lock (this)
            {
                CommandNumber++;
                // ReSharper disable once CompareOfFloatsByEqualityOperator
                if (StateSaveProbability != 0.0)
                {
                    // S3 debug support
                    DebugStateSave();
                    LastStateSaveCommandNumber = CommandNumber;
                }

                CommandHeader commandHeader;
                TpmHandle[]   inHandles;
                SessionIn[]   inSessions;
                byte[]        commandParmsNoHandles;
                bool          legalCommand = CommandProcessor.CrackCommand(inBuf, out commandHeader, out inHandles, out inSessions, out commandParmsNoHandles);

                if (!legalCommand)
                {
                    // Is a diagnostics command.  Pass through to TPM (a real RM would refuse).
                    TpmDevice.DispatchCommand(active, inBuf, out outBuf);
                    return;
                }

                TpmCc commandCode = commandHeader.CommandCode;

                // Lookup command
                CommandInfo command = Tpm2.CommandInfoFromCommandCode(commandCode);
                if (command == null)
                {
                    throw new Exception("Unrecognized command");
                }

                if (commandCode == TpmCc.ContextLoad || commandCode == TpmCc.ContextSave)
                {
                    //throw new Exception("ContextLoad and ContextSave not supported in this build");
                    Console.Error.WriteLine("ContextLoad and ContextSave not supported in this build");
                    outBuf = Marshaller.GetTpmRepresentation(new Object[] {
                        TpmSt.NoSessions,
                        (uint)10,
                        TpmRc.NotUsed
                    });
                }

                // Look up referenced objects and sessions
                ObjectContext[] neededObjects  = GetReferencedObjects(caller, inHandles);
                ObjectContext[] neededSessions = GetSessions(caller, inSessions);
                if (neededObjects == null || neededSessions == null)
                {
                    // This means that one or more of the handles was not registered for the context
                    byte[] ret = FormatError(TpmRc.Handle);
                    outBuf = ret;
                    return;
                }

                // Load referenced objects and sessions (free slots if needed)
                bool loadOk  = LoadEntities(neededObjects);
                bool loadOk2 = LoadEntities(neededSessions);
                if (!loadOk || !loadOk2)
                {
                    throw new Exception("Failed to make space for objects or sessions at to execute command");
                }

                // At this point everything referenced should be loaded, and there will be a free slot if needed
                // so we can translate the input handles to the underlying handles
                ReplaceHandlesIn(inHandles, inSessions, neededObjects, neededSessions);

                // create the translated command from the various components we have been manipulating
                byte[] commandBuf = CommandProcessor.CreateCommand(commandHeader.CommandCode, inHandles, inSessions, commandParmsNoHandles);
                Debug.Assert(commandBuf.Length == inBuf.Length);

                byte[] responseBuf;

                // Todo: Virtualize GetCapability for handle enumeration.

                //
                // Execute command on underlying TPM device.
                // If we get an ObjectMemory or SessionMemory error we try to make more space and try again
                // Note: If the TPM device throws an error above we let it propagate out.  There should be no side
                // effects on TPM state that the TBS cares about.
                //
                do
                {
                    TpmDevice.DispatchCommand(active, commandBuf, out responseBuf);
                    TpmRc resCode = GetResultCode(responseBuf);
                    if (resCode == TpmRc.Success)
                    {
                        break;
                    }
                    if (resCode == TpmRc.ObjectMemory)
                    {
                        bool slotMade = MakeSpace(SlotType.ObjectSlot, neededObjects);
                        if (!slotMade)
                        {
                            throw new Exception("Failed to make an object slot in the TPM");
                        }
                        continue;
                    }
                    if (resCode == TpmRc.SessionMemory)
                    {
                        bool slotMade = MakeSpace(SlotType.SessionSlot, neededSessions);
                        if (!slotMade)
                        {
                            throw new Exception("Failed to make a session slot in the TPM");
                        }
                        continue;
                    }
                    break;
                } while (true);

                // Parse the response from the TPM
                // TODO: Make this use the new methods in Tpm2

                // ReSharper disable once UnusedVariable
                var          mOut = new Marshaller(responseBuf);
                TpmSt        responseTag;
                uint         responseParamSize;
                TpmRc        resultCode;
                TpmHandle[]  responseHandles;
                SessionOut[] responseSessions;
                byte[]       responseParmsNoHandles, responseParmsWithHandles;

                CommandProcessor.SplitResponse(responseBuf,
                                               command.HandleCountOut,
                                               out responseTag,
                                               out responseParamSize,
                                               out resultCode,
                                               out responseHandles,
                                               out responseSessions,
                                               out responseParmsNoHandles,
                                               out responseParmsWithHandles);

                // If we have an error there is no impact on the loaded sessions, but we update
                // the LRU values because the user will likely try again.
                if (resultCode != TpmRc.Success)
                {
                    outBuf = responseBuf;
                    UpdateLastUseCount(new[] { neededObjects, neededSessions });
                    return;
                }

                // Update TBS database with any newly created TPM objects
                ProcessUpdatedTpmState(caller, command, responseHandles, neededObjects);

                // And if there were any newly created objects use the new DB entries to translate the handles
                ReplaceHandlesOut(responseHandles);
                byte[] translatedResponse = CommandProcessor.CreateResponse(resultCode, responseHandles, responseSessions, responseParmsNoHandles);

                outBuf = translatedResponse;
                Debug.Assert(outBuf.Length == responseBuf.Length);
            } // lock(this)
        }
示例#21
0
        /// <summary>
        /// Creates a duplication blob for the current key that can be Imported as a child
        /// of newParent. Three forms are possible. GetPlaintextDuplicationBlob() allows
        /// plaintext-import. This function enables duplication with and without an
        /// inner wrapper (depending on whether innerWrapper is null)
        /// </summary>
        /// <param name="newParent"></param>
        /// <param name="innerWrapper"></param>
        /// <param name="encryptedWrappingKey"></param>
        /// <returns></returns>
        public TpmPrivate GetDuplicationBlob(
            TpmPublic newParent,
            SymmCipher innerWrapper,
            out byte[] encryptedWrappingKey)
        {
            byte[] encSensitive;
            if (innerWrapper == null)
            {
                // No inner wrapper
                encSensitive = Marshaller.ToTpm2B(sensitivePart.GetTpmRepresentation());
            }
            else
            {
                byte[] sens           = Marshaller.ToTpm2B(sensitivePart.GetTpmRepresentation());
                byte[] toHash         = Globs.Concatenate(sens, GetName());
                byte[] innerIntegrity = Marshaller.ToTpm2B(CryptoLib.HashData(publicPart.nameAlg, toHash));
                byte[] innerData      = Globs.Concatenate(innerIntegrity, sens);
                encSensitive = innerWrapper.Encrypt(innerData);
            }

            byte[]       seed, encSecret;
            SymDefObject symDef = GetSymDef(newParent);

            using (AsymCryptoSystem newParentPubKey = AsymCryptoSystem.CreateFrom(newParent))
            {
                switch (newParent.type)
                {
                case TpmAlgId.Rsa:
                    // The seed should be the same size as the symmKey
                    seed      = Globs.GetRandomBytes((symDef.KeyBits + 7) / 8);
                    encSecret = newParentPubKey.EncryptOaep(seed, DuplicateEncodingParms);
                    break;

                case TpmAlgId.Ecc:
                    EccPoint pubEphem;
                    seed = newParentPubKey.EcdhGetKeyExchangeKey(DuplicateEncodingParms,
                                                                 newParent.nameAlg,
                                                                 out pubEphem);
                    encSecret = Marshaller.GetTpmRepresentation(pubEphem);
                    break;

                default:
                    Globs.Throw <NotImplementedException>("GetDuplicationBlob: Unsupported algorithm");
                    encryptedWrappingKey = new byte[0];
                    return(new TpmPrivate());
                }
            }

            encryptedWrappingKey = encSecret;

            byte[] symKey = KDF.KDFa(newParent.nameAlg, seed, "STORAGE", publicPart.GetName(), new byte[0], symDef.KeyBits);

            byte[] dupSensitive;
            using (SymmCipher enc2 = SymmCipher.Create(symDef, symKey))
            {
                dupSensitive = enc2.Encrypt(encSensitive);
            }

            var npNameNumBits = CryptoLib.DigestSize(newParent.nameAlg) * 8;

            byte[] hmacKey = KDF.KDFa(newParent.nameAlg, seed, "INTEGRITY", new byte[0], new byte[0], npNameNumBits);

            byte[] outerDataToHmac = Globs.Concatenate(dupSensitive, publicPart.GetName());

            byte[] outerHmac = Marshaller.ToTpm2B(CryptoLib.HmacData(newParent.nameAlg, hmacKey, outerDataToHmac));

            byte[] dupBlob = Globs.Concatenate(outerHmac, dupSensitive);

            return(new TpmPrivate(dupBlob));
        }
示例#22
0
        /// <summary>
        /// Dispatch a command to the underlying TPM. This method implements all
        /// significant functionality. It examines the command stream and performs
        /// (approximately) the following actions:
        /// 1) If the command references a handle (session or transient object), then
        ///     TBS makes sure that the entity  is loaded. If it is, then the handle is
        ///     "translated" to the underlying TPM handle. If it is not, then TBS checks
        ///     to see if it has a saved context for the entity, and if so, loads it.
        /// 2) If the command will fill a slot, then TBS ensures that a slot is available.
        ///     It does this by ContextSaving the LRU entity of the proper type (that is
        ///     not used in this command).
        /// </summary>
        /// <param name="caller"></param>
        /// <param name="active"></param>
        /// <param name="inBuf"></param>
        /// <param name="outBuf"></param>
        /// <exception cref="Exception"></exception>
        internal void DispatchCommand(TbsContext caller, CommandModifier active, byte[] inBuf, out byte[] outBuf)
        {
            lock (this)
            {
                CommandNumber++;
                // ReSharper disable once CompareOfFloatsByEqualityOperator
                if (StateSaveProbability != 0.0)
                {
                    // S3 debug support
                    DebugStateSave();
                    LastStateSaveCommandNumber = CommandNumber;
                }

                CommandHeader commandHeader;
                TpmHandle[]   inHandles;
                SessionIn[]   inSessions;
                byte[]        commandParmsNoHandles;
                bool          legalCommand = CommandProcessor.CrackCommand(inBuf,
                                                                           out commandHeader, out inHandles, out inSessions, out commandParmsNoHandles);

                if (!legalCommand)
                {
                    // Is a diagnostics command.  Pass through to TPM (a real RM would refuse).
                    TpmDevice.DispatchCommand(active, inBuf, out outBuf);
                    return;
                }

                TpmCc cc = commandHeader.CommandCode;

                // Lookup command
                CommandInfo command = Tpm2.CommandInfoFromCommandCode(cc);
                if (command == null)
                {
                    throw new Exception("Unrecognized command");
                }

                if (cc == TpmCc.ContextLoad || cc == TpmCc.ContextSave)
                {
                    Debug.WriteLine("ContextLoad and ContextSave are not supported in this build");
                    outBuf = Marshaller.GetTpmRepresentation(new Object[] {
                        TpmSt.NoSessions,
                        (uint)10,
                        TpmRc.NotUsed
                    });
                }

                // Look up referenced objects and sessions
                ObjectContext[] neededObjects  = GetReferencedObjects(caller, inHandles);
                ObjectContext[] neededSessions = GetSessions(caller, inSessions);
                ObjectContext[] neededEntities =
                    neededObjects != null
                            ? neededSessions != null
                                ? neededObjects.Concat(neededSessions).ToArray()
                                : neededObjects
                            : neededSessions;

#if false
                // LibTester may intentionally use invalid handles, therefore it always
                // work in the passthru mode (all correctness checks by TSS infra suppressed)
                if (!Tpm2._TssBehavior.Passthrough &&
                    (neededObjects == null || neededSessions == null))
#endif
                if (neededObjects == null || neededSessions == null)
                {
                    // One or more of the handles was not registered for the context
                    byte[] ret = FormatError(TpmRc.Handle);
                    outBuf = ret;
                    return;
                }

                // Load referenced objects and sessions (free slots if needed)
                // It's important to load all object and session handles in a single call
                // to LoadEntities(), as for some commands (e.g. GetSessionAuditDigest)
                // the objects array may contain session handles. In this case the session
                // handles loaded by the invocation of LoadEntities for neededObjects
                // may be evicted again during the subsequent call for neededSessions.
                var expectedResponses = Tpm._GetExpectedResponses();
                if (!LoadEntities(neededEntities))
                {
                    throw new Exception("Failed to make space for objects or sessions");
                }
                else
                {
                    // At this point everything referenced should be loaded, and
                    // there will be a free slot if needed so we can translate
                    // the input handles to the underlying handles
                    ReplaceHandlesIn(inHandles, inSessions, neededObjects, neededSessions);
                }

                // Re-create the command using translated object and session handles
                byte[] commandBuf = CommandProcessor.CreateCommand(commandHeader.CommandCode,
                                                                   inHandles, inSessions, commandParmsNoHandles);
                if (!Tpm2._TssBehavior.Passthrough)
                {
                    Debug.Assert(commandBuf.Length == inBuf.Length);
                }

                byte[] responseBuf;

                // TODO: Virtualize TPM2_GetCapability() for handle enumeration.

                //
                // Execute command on underlying TPM device.
                // If we get an ObjectMemory or SessionMemory error we try to make more space and try again
                // Note: If the TPM device throws an error above we let it propagate out.  There should be no side
                // effects on TPM state that the TBS cares about.
                //
                ulong firstCtxSeqNum = 0;
                while (true)
                {
                    Tpm._ExpectResponses(expectedResponses);
                    TpmDevice.DispatchCommand(active, commandBuf, out responseBuf);

                    TpmRc res = GetResultCode(responseBuf);
                    if (res == TpmRc.Success ||
                        expectedResponses != null && expectedResponses.Contains(res))
                    {
                        break;
                    }

                    if (res == TpmRc.ContextGap)
                    {
                        ulong seqNum = ShortenSessionContextGap(firstCtxSeqNum);
                        if (seqNum == 0)
                        {
                            break;  // Failed to handle CONTEXT_GAP error
                        }
                        if (firstCtxSeqNum == 0)
                        {
                            firstCtxSeqNum = seqNum;
                        }

                        //if (firstCtxSeqNum != 0)
                        //    Console.WriteLine("DispatchCommand: CONTEXT_GAP handled");
                        continue;
                    }

                    var slotType = SlotType.NoSlot;
                    if (res == TpmRc.ObjectHandles || res == TpmRc.ObjectMemory)
                    {
                        slotType = SlotType.ObjectSlot;
                    }
                    else if (res == TpmRc.SessionHandles || res == TpmRc.SessionMemory)
                    {
                        slotType = SlotType.SessionSlot;
                    }
                    else
                    {
                        // Command failure not related to resources
                        break;
                    }
                    if (!MakeSpace(slotType, neededEntities))
                    {
                        // Failed to make an object slot in the TPM
                        responseBuf = TpmErrorHelpers.BuildErrorResponseBuffer(TpmRc.Memory);
                        break;
                    }
                }

                // Parse the response from the TPM
                TpmSt        responseTag;
                uint         responseParamSize;
                TpmRc        resultCode;
                TpmHandle[]  responseHandles;
                SessionOut[] responseSessions;
                byte[]       responseParmsNoHandles, responseParmsWithHandles;

                CommandProcessor.SplitResponse(responseBuf,
                                               command.HandleCountOut,
                                               out responseTag,
                                               out responseParamSize,
                                               out resultCode,
                                               out responseHandles,
                                               out responseSessions,
                                               out responseParmsNoHandles,
                                               out responseParmsWithHandles);

                // In case of an error there is no impact on the loaded sessions, but
                // we update the LRU values because the user will likely try again.
                if (resultCode != TpmRc.Success)
                {
                    outBuf = responseBuf;
                    UpdateLastUseCount(new[] { neededObjects, neededSessions });
                    return;
                }

                // Update TBS database with any newly created TPM objects
                ProcessUpdatedTpmState(caller, command, responseHandles, neededObjects);

                // And if there were any newly created objects use the new DB entries
                // to translate the handles
                ReplaceHandlesOut(responseHandles);
                outBuf = CommandProcessor.CreateResponse(resultCode, responseHandles,
                                                         responseSessions, responseParmsNoHandles);

                Debug.Assert(outBuf.Length == responseBuf.Length);
            } // lock(this)
        }
示例#23
0
 internal override TpmHash GetPolicyDigest(TpmAlgId hashAlg)
 {
     return(GetNextAcePolicyDigest(hashAlg)
            .Extend(Marshaller.GetTpmRepresentation(TpmCc.PolicyPhysicalPresence)));
 }