Пример #1
0
        void ActivateAikSample(Tpm2 tpm, TestContext testCtx)
        {
            // Use an RSA primary key in the Endorsement hierarchy (EK) to 'activate'
            // another primary in the Endorsement hierarchy (AIK).

            // Note: this procedure can be used to activate a key in the Storage hierarchy, too.

            // "Activation" means secure passing sensitive data generated by a CA (e.g.
            // a symmetric key protecting a freshly generated certificate), so that only
            // a device with the TPM owning the target AIK and EK can access these data.

            // Create a primary key that we will certify.

            //////////////////////////////////////////////////////////////////////////////
            // Device side code
            //////////////////////////////////////////////////////////////////////////////

            // Name algorithm of the new AIK
            TpmAlgId nameAlg = TpmAlgId.Sha256;

            // The key to be certified needs a policy. It can be ANY policy, but here
            // it is configured to allow AIK usage only with the following commands
            var policyAIK = new PolicyTree(nameAlg);
            var policyOR  = new TpmPolicyOr();

            policyAIK.SetPolicyRoot(policyOR);
            policyOR.AddPolicyBranch(new TpmPolicyCommand(TpmCc.ActivateCredential, "Activate"));
            policyOR.AddPolicyBranch(new TpmPolicyCommand(TpmCc.Certify, "Certify"));
            policyOR.AddPolicyBranch(new TpmPolicyCommand(TpmCc.CertifyCreation, "CertifyCreation"));
            policyOR.AddPolicyBranch(new TpmPolicyCommand(TpmCc.Quote, "Quote"));

            var inAIKPub = new TpmPublic(nameAlg,
                                         ObjectAttr.Restricted | ObjectAttr.Sign | ObjectAttr.FixedParent | ObjectAttr.FixedTPM
                                         | ObjectAttr.AdminWithPolicy | ObjectAttr.SensitiveDataOrigin,
                                         policyAIK.GetPolicyDigest(),
                                         new RsaParms(new SymDefObject(), new SchemeRsassa(TpmAlgId.Sha256), 2048, 0),
                                         new Tpm2bPublicKeyRsa());

            TpmPublic    AIKpub;
            var          inSens = new SensitiveCreate(Substrate.RandomAuth(nameAlg), null);
            CreationData creationData;

            byte[]     creationHash;
            TkCreation creationTk;
            TpmHandle  hAIK = tpm.CreatePrimary(TpmRh.Endorsement, inSens, inAIKPub, null, null, out AIKpub,
                                                out creationData, out creationHash, out creationTk);
            // An alternative using test substrate helper
            //TpmHandle hAIK = Substrate.CreatePrimary(tpm, inAIKPub, TpmRh.Endorsement);

            // Normally a device would have a pre-provisioned persistent EK with the above handle
            TpmHandle hEK = new TpmHandle(0x81010001);

            // Get its public part
            TpmPublic EKpub = null;

            // In a test environment the real EK may be absent. In this case use
            // a primary key temporarily created in the Endorsement hierarchy.
            byte[] name, qname;
            tpm._AllowErrors()
            .ReadPublic(hEK, out name, out qname);
            if (!tpm._LastCommandSucceeded())
            {
                var inEKpub = new TpmPublic(TpmAlgId.Sha256,
                                            ObjectAttr.Restricted | ObjectAttr.Decrypt | ObjectAttr.FixedParent | ObjectAttr.FixedTPM
                                            | ObjectAttr.AdminWithPolicy | ObjectAttr.SensitiveDataOrigin,
                                            new byte[] { 0x83, 0x71, 0x97, 0x67, 0x44, 0x84, 0xb3, 0xf8,
                                                         0x1a, 0x90, 0xcc, 0x8d, 0x46, 0xa5, 0xd7, 0x24,
                                                         0xfd, 0x52, 0xd7, 0x6e, 0x06, 0x52, 0x0b, 0x64,
                                                         0xf2, 0xa1, 0xda, 0x1b, 0x33, 0x14, 0x69, 0xaa },
                                            new RsaParms(new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb), null, 2048, 0),
                                            new Tpm2bPublicKeyRsa());

                inSens = new SensitiveCreate(null, null);
                hEK    = tpm.CreatePrimary(TpmRh.Endorsement, inSens, inEKpub, null, null, out EKpub,
                                           out creationData, out creationHash, out creationTk);
            }

            // Marshal public parts of AIK and EK

            byte[] AIKpubBytes = AIKpub.GetTpmRepresentation();
            byte[] EKpubBytes  = EKpub.GetTpmRepresentation();

            // Here the device uses network to pass AIKpubBytes and EKpubBytes (as well as
            // the EK certificate) to CA service.


            //////////////////////////////////////////////////////////////////////////////
            // Service (CA) side code
            //////////////////////////////////////////////////////////////////////////////

            // Unmarshal AIKpub and EKpub (and EK certificate)

            var m = new Marshaller(AIKpubBytes);

            AIKpub = m.Get <TpmPublic>();
            m      = new Marshaller(EKpubBytes);
            EKpub  = m.Get <TpmPublic>();

            // Symmetric key to be used by CA to encrypt the new certificate it creates for AIK
            byte[] secretKey = Substrate.RandomBytes(32);

            // Here CA does the following (the sample does not show this code):
            // - Validates EK certificate
            // - Generates a new certificate for AIK (AIKcert)
            // - Encrypts AIKcert with secretKey

            // Create an activation blob

            // Internal wrapper key encrypted with EKpub to be used by TPM2_ActivateCredential() command.
            byte[] encSecret;

            // An encrypted and HMACed object tied to the destination TPM. It contains
            // 'secret' to be extracted by the successful TPM2_ActivateCredential() command
            // (that can only succeeed on the TPM that originated both EK and AIK).
            IdObject certInfo;

            // Run TSS.Net equivalent of TPM2_MakeCredential() command (convenient for the server side,
            // as it will likely be faster than the TPM transaction and allows concurrent execution).
            certInfo = EKpub.CreateActivationCredentials(secretKey, AIKpub.GetName(), out encSecret);

            // Marshal certInfo

            // IdObject data type requires customized marshaling
            m = new Marshaller();
            m.Put(certInfo.integrityHMAC.Length, "integrityHMAC.Length");
            m.Put(certInfo.integrityHMAC, "integrityHMAC");
            m.Put(certInfo.encIdentity.Length, "encIdentity");
            m.Put(certInfo.encIdentity, "encIdentity.Length");
            byte[] certInfoBytes = m.GetBytes();

            // Here the CA passes certInfoBytes and encSecret (as well as the encrypted
            // AIK certificate) back to the device via network.


            //////////////////////////////////////////////////////////////////////////////
            // Device side code again
            //////////////////////////////////////////////////////////////////////////////

            // Unmarshal certInfo and encSecret (and encrypted AIK certificate)

            m = new Marshaller(certInfoBytes);
            int len = m.Get <int>();

            certInfo.integrityHMAC = m.GetArray <byte>(len);
            len = m.Get <int>();
            certInfo.encIdentity = m.GetArray <byte>(len);
            // encSecret is a byte array, so, normally, no special unmarshalling is required

            // Create policy session to authorize AIK usage
            AuthSession sessAIK = tpm.StartAuthSessionEx(TpmSe.Policy, nameAlg);

            sessAIK.RunPolicy(tpm, policyAIK, "Activate");

            // Create policy description and corresponding policy session to authorize EK usage
            var policyEK = new PolicyTree(EKpub.nameAlg);

            policyEK.SetPolicyRoot(new TpmPolicySecret(TpmRh.Endorsement, false, 0, null, null));

            AuthSession sessEK = tpm.StartAuthSessionEx(TpmSe.Policy, EKpub.nameAlg);

            sessEK.RunPolicy(tpm, policyEK);

            byte[] recoveredSecretKey = tpm[sessAIK, sessEK].ActivateCredential(hAIK, hEK, certInfo, encSecret);

            testCtx.AssertEqual("Secret.1", recoveredSecretKey, secretKey);

            // Here the device can use recoveredSecretKey to decrypt the AIK certificate

            //////////////////////////////////////////////////////////////////////////////
            // End of activation sequence
            //////////////////////////////////////////////////////////////////////////////


            //
            // Now prepare activation using the TPM built-in command
            //

            byte[]   encSecret2 = null;
            IdObject certInfo2  = tpm.MakeCredential(hEK, secretKey, AIKpub.GetName(), out encSecret2);

            // Reinitialize policy sessions
            tpm.PolicyRestart(sessAIK);
            sessAIK.RunPolicy(tpm, policyAIK, "Activate");
            tpm.PolicyRestart(sessEK);
            sessEK.RunPolicy(tpm, policyEK);

            recoveredSecretKey = tpm[sessAIK, sessEK].ActivateCredential(hAIK, hEK, certInfo2, encSecret2);
            testCtx.AssertEqual("Secret.2", recoveredSecretKey, secretKey);

            // Cleanup
            tpm.FlushContext(sessAIK);
            tpm.FlushContext(sessEK);
            tpm.FlushContext(hAIK);

            if (hEK.handle != 0x81010001)
            {
                tpm.FlushContext(hEK);
            }
        } // ActivateAikSample
Пример #2
0
 private TpmRc GetResultCode(byte[] responseBuf)
 {
     var mOut = new Marshaller(responseBuf);
     // ReSharper disable once UnusedVariable
     var responseTag = mOut.Get<TpmSt>();
     // ReSharper disable once UnusedVariable
     var responseParamSize = mOut.Get<uint>();
     var resultCode = mOut.Get<TpmRc>();
     return resultCode;
 }
Пример #3
0
        /// <summary>
        /// Activates an identity key within the TPM device.
        /// </summary>
        /// <param name="encryptedKey">The encrypted identity key.</param>
        public override void ActivateIdentityKey(byte[] encryptedKey)
        {
            if (Logging.IsEnabled)
            {
                Logging.Enter(this, $"{encryptedKey}", nameof(ActivateIdentityKey));
            }
            Destroy();

            // Take the pieces out of the container
            var           m      = new Marshaller(encryptedKey, DataRepresentation.Tpm);
            Tpm2bIdObject cred2b = m.Get <Tpm2bIdObject>();

            byte[] encryptedSecret = new byte[m.Get <ushort>()];
            encryptedSecret = m.GetArray <byte>(encryptedSecret.Length, "encryptedSecret");
            TpmPrivate dupBlob = m.Get <TpmPrivate>();

            byte[] encWrapKey = new byte[m.Get <ushort>()];
            encWrapKey = m.GetArray <byte>(encWrapKey.Length, "encWrapKey");
            UInt16 pubSize = m.Get <UInt16>();

            _idKeyPub = m.Get <TpmPublic>();
            byte[] cipherText = new byte[m.Get <ushort>()];
            cipherText = m.GetArray <byte>(cipherText.Length, "uriInfo");

            // Setup the authorization session for the EK
            var policyNode = new TpmPolicySecret(TpmHandle.RhEndorsement, false, 0, Array.Empty <byte>(), Array.Empty <byte>());
            var policy     = new PolicyTree(_ekPub.nameAlg);

            policy.SetPolicyRoot(policyNode);
            AuthSession ekSession = _tpm2.StartAuthSessionEx(TpmSe.Policy, _ekPub.nameAlg);

            ekSession.RunPolicy(_tpm2, policy);

            // Perform the activation
            ekSession.Attrs  &= ~SessionAttr.ContinueSession;
            _activationSecret = _tpm2[Array.Empty <byte>(), ekSession].ActivateCredential(
                new TpmHandle(TPM_20_SRK_HANDLE),
                new TpmHandle(TPM_20_EK_HANDLE),
                cred2b.credential,
                encryptedSecret);

            TpmPrivate importedKeyBlob = _tpm2.Import(
                new TpmHandle(TPM_20_SRK_HANDLE),
                _activationSecret,
                _idKeyPub,
                dupBlob,
                encWrapKey,
                new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb));

            _idKeyHandle = _tpm2.Load(new TpmHandle(TPM_20_SRK_HANDLE), importedKeyBlob, _idKeyPub);

            // Persist the key in NV
            TpmHandle hmacKeyHandle = new TpmHandle(AIOTH_PERSISTED_KEY_HANDLE);

            _tpm2.EvictControl(new TpmHandle(TpmRh.Owner), _idKeyHandle, hmacKeyHandle);

            // Unload the transient copy from the TPM
            _tpm2.FlushContext(_idKeyHandle);
            _idKeyHandle = hmacKeyHandle;

            if (Logging.IsEnabled)
            {
                Logging.Exit(this, $"{encryptedKey}", nameof(ActivateIdentityKey));
            }
        }
Пример #4
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();
 }
        /// <summary>
        /// Activates a symmetric identity within the Hardware Security Module.
        /// </summary>
        /// <param name="activation">The authentication challenge key supplied by the service.</param>
        public override void ActivateSymmetricIdentity(byte[] activation)
        {
            Destroy();

            // Take the pieces out of the container
            var m = new Marshaller(activation, DataRepresentation.Tpm);

            byte[] credentialBlob = new byte[m.Get <ushort>()];
            credentialBlob = m.GetArray <byte>(credentialBlob.Length, "credentialBlob");
            byte[] encryptedSecret = new byte[m.Get <ushort>()];
            encryptedSecret = m.GetArray <byte>(encryptedSecret.Length, "encryptedSecret");
            TpmPrivate dupBlob = m.Get <TpmPrivate>();

            byte[] encWrapKey = new byte[m.Get <ushort>()];
            encWrapKey = m.GetArray <byte>(encryptedSecret.Length, "encWrapKey");
            UInt16 pubSize = m.Get <UInt16>();

            _idKeyPub = m.Get <TpmPublic>();
            byte[] cipherText = new byte[m.Get <ushort>()];
            cipherText = m.GetArray <byte>(cipherText.Length, "uriInfo");

            // Setup the authorization session for the EK
            var policyNode = new TpmPolicySecret(
                TpmHandle.RhEndorsement, _ekAuth ?? Array.Empty <byte>(),
                new AuthValue(),
                false,
                0,
                Array.Empty <byte>(),
                Array.Empty <byte>());

            var policy = new PolicyTree(_ekPub.nameAlg);

            policy.SetPolicyRoot(policyNode);
            AuthSession ekSession = _tpm2.StartAuthSessionEx(TpmSe.Policy, _ekPub.nameAlg);

            ekSession.RunPolicy(_tpm2, policy);

            // Perform the activation
            ekSession.Attrs  &= ~SessionAttr.ContinueSession;
            _activationSecret = _tpm2[Array.Empty <byte>(), ekSession].ActivateCredential(
                new TpmHandle(TPM_20_SRK_HANDLE),
                new TpmHandle(TPM_20_EK_HANDLE),
                credentialBlob,
                encryptedSecret);

            TpmPrivate importedKeyBlob = _tpm2.Import(
                new TpmHandle(TPM_20_SRK_HANDLE),
                _activationSecret,
                _idKeyPub,
                dupBlob,
                encWrapKey,
                new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb));

            _idKeyHandle = _tpm2.Load(new TpmHandle(TPM_20_SRK_HANDLE), importedKeyBlob, _idKeyPub);

            // Persist the key in NV
            TpmHandle hmacKeyHandle = new TpmHandle(AIOTH_PERSISTED_KEY_HANDLE);

            _tpm2.EvictControl(new TpmHandle(TpmRh.Owner), _idKeyHandle, hmacKeyHandle);

            // Unload the transient copy from the TPM
            _tpm2.FlushContext(_idKeyHandle);
            _idKeyHandle = hmacKeyHandle;

            // Unwrap the URI
            byte[] clearText = SymmCipher.Decrypt(
                new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb),
                _activationSecret,
                new byte[16],
                cipherText);

            UnicodeEncoding unicode = new UnicodeEncoding();
            string          uriData = unicode.GetString(clearText);
            int             idx     = uriData.IndexOf('/');

            if (idx > 0)
            {
                string hostName = uriData.Substring(0, idx);
                string deviceId = uriData.Substring(idx + 1);

                // Persist the URI
                ProvisionUri(hostName, deviceId);
            }
        }
Пример #6
0
        public static TpmRc GetResponseCode(byte[] response)
        {
            if (response.Length > 10)
                return TpmRc.Success;

            var m = new Marshaller(response);
            // ReSharper disable once UnusedVariable
            var tag = m.Get<TpmSt>();
            // ReSharper disable once UnusedVariable
            var paramSize = m.Get<uint>();
            var responseCode = m.Get<TpmRc>();
            TpmRc maskedResponse = Tpm2.GetBaseErrorCode(responseCode);
            return maskedResponse;

        }
Пример #7
0
        public static string ParseResponse(string commandCode, byte[] buf)
        {
            TpmHandle[] outHandles;
            SessionOut[] outSessions;
            byte[] responseParmsNoHandles;
            byte[] responseParmsWithHandles;
            string response = "";
            if (1 != CommandInformation.Info.Count(item => item.CommandCode.ToString() == commandCode))
            {
                response = "Command code not recognized.  Defined command codes are:\n";
                // ReSharper disable once LoopCanBeConvertedToQuery
                foreach (CommandInfo info in CommandInformation.Info)
                {
                    response += info.CommandCode.ToString() + " ";
                }
                return response;
            }

            CommandInfo command = CommandInformation.Info.First(item => item.CommandCode.ToString() == commandCode);
            TpmSt tag;
            uint paramSize;
            TpmRc responseCode;

            SplitResponse(buf,
                          command.HandleCountOut,
                          out tag,
                          out paramSize,
                          out responseCode,
                          out outHandles,
                          out outSessions,
                          out responseParmsNoHandles,
                          out responseParmsWithHandles);
            if (responseCode != TpmRc.Success)
            {
                TpmRc resultCode;
                response += "Error:\n";
                response += Tpm2.GetErrorString(command.InStructType, (uint)responseCode, out resultCode);
                return response;
            }

            // At this point in the processing stack we cannot deal with encrypted responses
            bool responseIsEncrypted = false;
            foreach (SessionOut s in outSessions)
            {
                if (s.attributes.HasFlag(SessionAttr.Encrypt)
                    &&
                    (command.TheParmCryptInfo.HasFlag(ParmCryptInfo.DecOut2) ||
                     command.TheParmCryptInfo.HasFlag(ParmCryptInfo.DecOut2))
                    )
                    responseIsEncrypted = true;
            }

            response += "Response Header:\n";
            response += "    Tag=" + tag.ToString() + "\n";
            response += "    Response code=" + responseCode.ToString() + "\n";

            response += "Response Parameters:\n";
            if (!responseIsEncrypted)
            {
                var m2 = new Marshaller(responseParmsWithHandles);
                Object inParms = m2.Get(command.OutStructType, "");
                response += inParms + "\n";
            }
            else
            {
                var m2 = new Marshaller(responseParmsWithHandles);
                Object encOutParms;
                switch (command.TheParmCryptInfo)
                {
                    // TODO: this is not the right type if we ever do size-checks
                    case ParmCryptInfo.DecOut2:
                        encOutParms = m2.Get(typeof (Tpm2bMaxBuffer), "");
                        break;
                    default:
                        throw new NotImplementedException("NOT IMPLEMENTED");
                }
                response += "Encrypted: " + encOutParms + "\n";
            }

            response += "Sessions [" + outSessions.Length + "]\n";
            for (int j = 0; j < outSessions.Length; j++)
            {
                // ReSharper disable once FormatStringProblem
                response += String.Format("{0}: 0x{1:x}\n", j, outSessions[j]);
            }
            return response;
        }
Пример #8
0
        public static void SplitResponse(
            byte[] response,
            uint numHandles,
            out TpmSt tag,
            out uint paramSize,
            out TpmRc responseCode,
            out TpmHandle[] handles,
            out SessionOut[] sessions,
            out byte[] responseParmsNoHandles,
            out byte[] responseParmsWithHandles)
        {
            var m = new Marshaller(response);
            tag = m.Get<TpmSt>();
            paramSize = m.Get<uint>();
            responseCode = m.Get<TpmRc>();
            // If error we only get the header
            if (responseCode != TpmRc.Success)
            {
                handles = new TpmHandle[0];
                sessions = new SessionOut[0];
                responseParmsNoHandles = new byte[0];
                responseParmsWithHandles = new byte[0];
                return;
            }

            handles = new TpmHandle[numHandles];
            for (int j = 0; j < numHandles; j++)
            {
                handles[j] = m.Get<TpmHandle>();
            }
            uint parmsEnd = m.GetValidLength();
            if (tag == TpmSt.Sessions)
            {
                var sessionOffset = m.Get<uint>();
                uint startOfParmsX = m.GetGetPos();
                parmsEnd = startOfParmsX + sessionOffset;
                m.SetGetPos(parmsEnd);
                var sessX = new List<SessionOut>();
                while (m.GetGetPos() < m.GetValidLength())
                {
                    var s = m.Get<SessionOut>();
                    sessX.Add(s);
                }
                sessions = sessX.ToArray();
                m.SetGetPos(startOfParmsX);
            }
            else
            {
                sessions = new SessionOut[0];
            }

            uint startOfParms = m.GetGetPos();
            uint parmsLength = parmsEnd - m.GetGetPos();

            // Get the response buf with no handles
            responseParmsNoHandles = new byte[parmsLength];
            Array.Copy(response, (int)startOfParms, responseParmsNoHandles, 0, (int)parmsLength);

            // Get the response buf with handles
            responseParmsWithHandles = new byte[parmsLength + numHandles * 4];
            Array.Copy(response, 10, responseParmsWithHandles, 0, (int)numHandles * 4);
            Array.Copy(response, (int)startOfParms, responseParmsWithHandles, (int)numHandles * 4, (int)parmsLength);
        }
Пример #9
0
        public static string ParseCommand(byte[] buf)
        {
            CommandHeader commandHeader;
            TpmHandle[] inHandles;
            SessionIn[] inSessions;
            byte[] commandParmsNoHandles;
            string response = "";

            bool ok = CrackCommand(buf, out commandHeader, out inHandles, out inSessions, out commandParmsNoHandles);
            if (!ok)
            {
                response = "The TPM command is not properly formatted.  Doing the best I can...\n";
            }
            CommandInfo command = Tpm2.CommandInfoFromCommandCode(commandHeader.CommandCode);
            if (command == null)
            {
                response += String.Format("The command-code {0} is not defined.  Aborting\n", commandHeader.CommandCode);
                return response;
            }
            response += "Header:\n";
            response += commandHeader + "\n";

            var m2 = new Marshaller();
            foreach (TpmHandle h in inHandles)
            {
                m2.Put(h, "");
            }

            byte[] commandParmsWithHandles = Globs.Concatenate(new[] {m2.GetBytes(), commandParmsNoHandles});
            var m = new Marshaller(commandParmsWithHandles);
            object inParms = m.Get(command.InStructType, "");
            response += "Command Parameters:\n";
            response += inParms + "\n";
            response += "Sessions [" + inSessions.Length + "]\n";
            for (int j = 0; j < inSessions.Length; j++)
            {
                // ReSharper disable once FormatStringProblem
                response += String.Format("{0}: 0x{1:x}\n", j, inSessions[j]);
            }
            return response;
        }
Пример #10
0
        /// <summary>
        /// DispatchMethod is called by auto-generated command action code. It assembles a byte[] containing
        /// the formatted TPM command based on the params passed in explicitly, and the sessions currently attached
        /// to the TPM object.  It processes the TPM response and converts it into an instantiation of the 
        /// requested object.
        /// </summary>
        /// <param name="ordinal"></param>
        /// <param name="inParms"></param>
        /// <param name="expectedResponseType"></param>
        /// <param name="outParms"></param>
        /// <param name="numInHandlesNotUsed"></param>
        /// <param name="numOutHandlesNotUsed"></param>
        /// <returns></returns>
        internal bool DispatchMethod(
            TpmCc ordinal,
            TpmStructureBase inParms,
            Type expectedResponseType,
            out TpmStructureBase outParms,
            int numInHandlesNotUsed,
            int numOutHandlesNotUsed)
        {
            outParms = null;
            // todo - ClearCommandContext should be moved to the front of this
            // routine (and we should make local copies of the context-values we depend upon)
            // There are uncaught exceptions that can be generated that would skip
            // ClearCOmmandCOntext and leave the Tpm2 with some leftover state.

            byte[] response;

            if (CurrentCommand != TpmCc.None)
            {
                OuterCommand = CurrentCommand;
            }
            CurrentCommand = ordinal;

            // The AlternateActionCallback allows alternate processing (or filtering/data
            // collection on the executing command stream.
            if (TheAlternateActionCallback != null)
            {
                bool desiredSuccessCode;
                bool alternate = TheAlternateActionCallback(ordinal,
                                                            inParms,
                                                            expectedResponseType,
                                                            out outParms,
                                                            out desiredSuccessCode);
                if (alternate)
                {
                    _ClearCommandContext();
                    return desiredSuccessCode;
                }
            }

            CommandInfo commandInfo = CommandInfoFromCommandCode(ordinal);
            byte[] parms;
            TpmHandle[] inHandles;

            try
            {
                // Get the handles and the parameters from the command input structure
                CommandProcessor.Fragment(inParms, commandInfo.HandleCountIn, out inHandles, out parms);

                // Start processing sessions
                PrepareRequestSessions(commandInfo, inHandles);
            }
            catch (Exception e)
            {
                Debug.Assert(outParms == null);
                if (e is TpmException)
                {
                    if (IsErrorAllowed(((TpmException)e).RawResponse))
                    {
                        outParms = (TpmStructureBase)Activator.CreateInstance(expectedResponseType);
                    }
                }
                _ClearCommandPrelaunchContext();
                _ClearCommandContext();
                if (outParms != null)
                {
                    return false;
                }
                throw;
            }

            // The caller can install observer/modifier callbacks, and request repeated
            // execution of the same command.
            bool repeat = false;
            byte[] parmsCopy = null;

            if (TheCmdParamsCallback != null)
            {
                parmsCopy = Globs.CopyData(parms);
            }

            // Response atoms
            TpmSt responseTag;
            TpmRc resultCode;
            uint responseParamSize;
            byte[] outParmsNoHandles, outParmsWithHandles;
            TpmHandle[] outHandles;
            SessionOut[] outSessions;

            // In normal processing there is just one pass through this do-while loop
            // If command observation/modification callbacks are installed, then the
            // caller repeats the command as long as necessary.
            bool invokeCallbacks = OuterCommand == TpmCc.None && !CpHashMode && !DoNotDispatchCommand;
            do try
            {
                if (TheCmdParamsCallback != null && invokeCallbacks)
                {
                    parms = Globs.CopyData(parmsCopy);
                    TheCmdParamsCallback(commandInfo, ref parms, inHandles);
                }

                // If there are any encrypting sessions then next we encrypt the data in place
                parms = DoParmEncryption(parms, commandInfo, 0, Direction.Command);

                // Now do the HMAC (note that the handles are needed for name-replacement)
                SessionIn[] inSessions = CreateRequestSessions(parms, inHandles);

                // CpHashMode is enabled for a single command through tpm.GetCpHash().TpmCommand(...)
                if (OuterCommand == TpmCc.None && CpHashMode)
                {
                    CommandParmHash.HashData = GetCommandHash(CommandParmHash.HashAlg, parms, inHandles);
                    outParms = (TpmStructureBase)Activator.CreateInstance(expectedResponseType);
                    CpHashMode = false;
                    _ClearCommandContext();
                    return true;
                }

                // Create the command buffer
                byte[] command = CommandProcessor.CreateCommand(ordinal, inHandles, inSessions, parms);

                // And dispatch the command
                Log(ordinal, inParms, 0);

                if (DoNotDispatchCommand)
                {
                    CommandBytes = command;
                    outParms = (TpmStructureBase)Activator.CreateInstance(expectedResponseType);
                    DoNotDispatchCommand = false;
                    _ClearCommandContext();
                    return true;
                }

                if (TheCmdBufCallback != null && invokeCallbacks)
                {
                    TheCmdBufCallback(ref command);
                }

                // And actually dispatch the command into the underlying device
                DateTime commandSentTime, responseReceivedTime;
                int nvRateRecoveryCount = 0;

                // No more than 4 retries on NV_RATE error
                for (;;)
                {
                    responseReceivedTime = commandSentTime = DateTime.Now;

                    if (!TestCycleNv)
                    {
                        commandSentTime = DateTime.Now;
                        Device.DispatchCommand(ActiveModifiers, command, out response);
                        responseReceivedTime = DateTime.Now;
                    }
                    else
                    {
                        // In TestCycleNv we submit the command with NV not-available.  If the TPM indicates that
                        // NV is not available we re-submit.
                        try
                        {
                            // Once with NV off
                            Device.SignalNvOff();
                            Device.DispatchCommand(ActiveModifiers, command, out response);
                            Device.SignalNvOn();
                            // And if it did not work, try again with NV on
                            TpmRc respCode = CommandProcessor.GetResponseCode(response);
                            if ((uint)respCode == 0x923U || respCode == TpmRc.Lockout)
                            {
                                Device.DispatchCommand(ActiveModifiers, command, out response);
                            }

                        }
                        catch (Exception)
                        {
                            Device.SignalNvOn();
                            throw;
                        }
                    }

                    // Convert the byte[] response into its constituent parts.
                    CommandProcessor.SplitResponse(response,
                                                   commandInfo.HandleCountOut,
                                                   out responseTag,
                                                   out responseParamSize,
                                                   out resultCode,
                                                   out outHandles,
                                                   out outSessions,
                                                   out outParmsNoHandles,
                                                   out outParmsWithHandles);

                    if (resultCode != TpmRc.NvRate || ++nvRateRecoveryCount > 4)
                    {
                        break;
                    }
                    //Console.WriteLine(">>>> NV_RATE: Retrying... Attempt {0}", nvRateRecoveryCount);
                    Thread.Sleep((int)Tpm2.GetProperty(this, Pt.NvWriteRecovery) + 100);
                }

                // Invoke the trace callback if installed        
                if (TheTraceCallback != null)
                {
                    TheTraceCallback(command, response);
                }

                // Collect basic statistics on command execution
                if (TheCmdStatsCallback != null && invokeCallbacks)
                {
                    repeat = TheCmdStatsCallback(ordinal, GetBaseErrorCode(resultCode),
                                        (responseReceivedTime - commandSentTime).TotalSeconds);
                }

                if (repeat && resultCode == TpmRc.Success)
                {
                    // Update session state
                    ProcessResponseSessions(outSessions);
                    int offset = (int)commandInfo.HandleCountOut * 4;
                    outParmsWithHandles = DoParmEncryption(outParmsWithHandles, commandInfo, offset, Direction.Response);
                    var m = new Marshaller(outParmsWithHandles);
                    outParms = (TpmStructureBase)m.Get(expectedResponseType, "");
#if false
                    m = new Marshaller(command);
                    TpmSt tag = m.Get<TpmSt>();
                    uint cmdSize = m.Get<uint>();
                    TpmCc actualCmd = m.Get<TpmCc>();
                    var actualHandles = new TpmHandle[inHandles.Length];
                    for (int i = 0; i < inHandles.Length; ++i)
                    {
                        actualHandles[i] = m.Get<TpmHandle>();
                    }
                    for (int i = 0; i < inSessions.Length; ++i)
                    {
                        m.Get<SessionIn>();
                    }
                    var actualParms = m.GetArray<byte>(m.GetValidLength() - m.GetGetPos());
                    if (m.GetValidLength() != cmdSize)
                    {
                        throw new Exception("Command length in header does not match input byte-stream");
                    }
#endif
                    CommandHeader actualHeader;
                    TpmHandle[] actualHandles;
                    SessionIn[] actualSessions;
                    byte[] actualParmsBuf;
                    CommandProcessor.CrackCommand(command, out actualHeader, out actualHandles, out actualSessions, out actualParmsBuf);
                    m = new Marshaller();
                    foreach (TpmHandle h in actualHandles)
                    {
                        m.Put(h, "handle");
                    }
                    m.Put(actualParmsBuf, "parms");
                    var actualParms = (TpmStructureBase)Activator.CreateInstance(inParms.GetType());
                    actualParms.ToHost(m);
                    UpdateHandleData(actualHeader.CommandCode, actualParms, actualHandles, outParms);
                    //ValidateResponseSessions(outHandles, outSessions, ordinal, resultCode, outParmsNoHandles);

                    foreach (var h in outHandles)
                    {
                        CancelSafeFlushContext(h);
                    }
                } // if (repeat && resultCode == TpmRc.Success)
            }
            catch (Exception)
            {
                _ClearCommandPrelaunchContext();
                _ClearCommandContext();
                throw;
            }
            while (repeat);

            // Update the audit session if needed
            if (AuditThisCommand)
            {
                AuditThisCommand = false;
                if (CommandAuditHash == null)
                    throw new Exception("No audit hash set for this command stream");
                byte[] parmHash = GetCommandHash(CommandAuditHash.HashAlg, parms, inHandles);
                byte[] expectedResponseHash = GetExpectedResponseHash(CommandAuditHash.HashAlg,
                                                                      outParmsNoHandles,
                                                                      ordinal,
                                                                      resultCode);
                CommandAuditHash.Extend(Globs.Concatenate(parmHash, expectedResponseHash));
            }

            // FlushContest that may be executed as part of _ClearCommandPrelaunchContext()
            // must be executed before any command-related info is updated.
            _ClearCommandPrelaunchContext();

            // Process errors if there are any
            bool commandSucceeded = ProcessError(responseTag, responseParamSize, resultCode, inParms);
            try
            {
                if (commandSucceeded)
                {
                    ProcessResponseSessions(outSessions);
                    int offset = (int)commandInfo.HandleCountOut * 4;
                    outParmsWithHandles = DoParmEncryption(outParmsWithHandles, commandInfo, offset, Direction.Response);

                    var mt = new Marshaller(outParmsWithHandles);
                    outParms = (TpmStructureBase)mt.Get(expectedResponseType, "");
                    if (TheParamsTraceCallback != null)
                    {
                        TheParamsTraceCallback(ordinal, inParms, outParms);
                    }

                    UpdateHandleData(ordinal, inParms, inHandles, outParms);
                    ValidateResponseSessions(outHandles, outSessions, ordinal, resultCode, outParmsNoHandles);

                    foreach (var s in Sessions) if (s is AuthSession)
                    {
                        var sess = s as AuthSession;
                        if (sess.Attrs.HasFlag(SessionAttr.Audit) && !TpmHandle.IsNull(sess.BindObject))
                        {
                            sess.BindObject = TpmRh.Null;
                            break; // only one audit session is expected
                        }
                    }
                }
                else
                {
                    outParms = (TpmStructureBase)Activator.CreateInstance(expectedResponseType);
                }
            }
            finally
            {
                // Check in case an exception happened before outParms was initialized
                // ReSharper disable once CSharpWarnings::CS0183
                if (outParms is TpmStructureBase)
                {
                    Log(ordinal, outParms, 1);
                }
                // Clear all per-invocation state (e.g. sessions, errors expected) ready for next command
                _ClearCommandContext();
            }
            return commandSucceeded;
        }
Пример #11
0
 /// <summary>
 /// Opens a properly-formed TPM command stream into its constituent components.
 /// Note: commandParams does NOT include handles.
 /// </summary>
 /// <param name="command"></param>
 /// <param name="header"></param>
 /// <param name="handles"></param>
 /// <param name="sessions"></param>
 /// <param name="commandParms"></param>
 public static bool CrackCommand(
     byte[] command,
     out CommandHeader header,
     out TpmHandle[] handles,
     out SessionIn[] sessions,
     out byte[] commandParms)
 {
     var m = new Marshaller(command);
     header = m.Get<CommandHeader>();
     CommandInfo commandInfo = Tpm2.CommandInfoFromCommandCode(header.CommandCode);
     if (header.Tag == TpmSt.Null)
     {
         // A diagnostics command. Pass through unmodified
         handles = null;
         sessions = null;
         commandParms = null;
         return false;
     }
     handles = new TpmHandle[commandInfo.HandleCountIn];
     for (int j = 0; j < handles.Length; j++)
     {
         handles[j] = m.Get<TpmHandle>();
     }
     // Note sessions are only present if the command tag indicates sessions
     if (header.Tag == TpmSt.Sessions)
     {
         var sessionLength = m.Get<uint>();
         uint sessionEnd = m.GetGetPos() + sessionLength;
         var inSessions = new List<SessionIn>();
         while (m.GetGetPos() < sessionEnd)
         {
             var s = m.Get<SessionIn>();
             inSessions.Add(s);
         }
         sessions = inSessions.ToArray();
     }
     else
     {
         sessions = new SessionIn[0];
     }
     // And finally parameters
     commandParms = m.GetArray<byte>((int)(m.GetValidLength() - m.GetGetPos()));
     if (m.GetValidLength() != header.CommandSize)
     {
         throw new Exception("Command length in header does not match input byte-stream");
     }
     return true;
 }
Пример #12
0
        // This is installed as the raw command callback handler on the underlying TPM.
        // It is used to generate low-level test statistics (number of commands executed,
        // etc.), dumps of the conversation with the TPM and to keep a record of all
        // command sequences seen that contain types that we haven't seen before.
        // In the case of a multi-context TPM this will be called on different threads,
        // but locking should be handled safely by MainTestLogger.
        void ICommandCallbacks.PostCallback(byte[] inBuf, byte[] outBuf)
        {
            TimeSpan cmdExecutionTime = DateTime.Now - CurCmdStartTime;

            if (inBuf.Length < 10)
            {
                return;
            }
            Marshaller m           = new Marshaller(inBuf);
            TpmSt      sessionTag  = m.Get <TpmSt>();
            uint       parmSize    = m.Get <UInt32>();
            TpmCc      commandCode = m.Get <TpmCc>();

            if (commandCode == TpmCc.Clear)
            {
                ClearWasExecuted = true;
            }

            Marshaller mOut              = new Marshaller(outBuf);
            TpmSt      responseTag       = mOut.Get <TpmSt>();
            uint       responseParamSize = mOut.Get <uint>();
            TpmRc      responseCode      = mOut.Get <TpmRc>();

            if (ValidateTestAttributes)
            {
                // ValidateTestAttributes should not be set for a stress run
                LogTestAttributes(sessionTag, commandCode);
                try
                {
                    if (responseCode == TpmRc.Success)
                    {
                        ValidateHandleUsage(commandCode, inBuf);
                    }
                }
                catch (Exception)
                {
                    // Invalid command buffer can mess this up
                }
            }

            if (sessionTag.Equals(TpmSt.Null))
            {
                return;
            }

            // There are two encoding for errors - formats 0 and 1. Decode the error type
            uint resultCodeValue    = (uint)responseCode;
            bool formatOneErrorType = ((resultCodeValue & 0x80) != 0);
            uint resultCodeMask     = formatOneErrorType ? 0xBFU : 0x97FU;

            TpmRc maskedError = (TpmRc)((uint)responseCode & resultCodeMask);

            lock (this)
            {
                // log the command info to the test logger so that it can collect stats
                LogCommandExecution(commandCode, maskedError, cmdExecutionTime);
            }

#if false
            // Keep a copy of successfully executed commands that contain types we have
            // not seen so far. This is for tests that need good-command candidate strings,
            // like TestCommandDispatcherCoverage.
            // Code 0x80280400 is returned by TBS when the command is blocked by Windows.
            if (maskedError == TpmRc.Success && !Tpm2.IsTbsError(resultCodeValue))
            {
                // look at all types in command string.  If we have a new type we keep it
                CrackedCommand cc   = CommandProcessor.CrackCommand(inBuf);
                CommandInfo    info = CommandInformation.Info.First(x =>
                                                                    x.CommandCode == cc.Header.CommandCode);
                byte[] inStructBytes = Globs.Concatenate(
                    Globs.GetZeroBytes((int)info.HandleCountIn * 4),
                    cc.CommandParms);
                Marshaller mx = new Marshaller(inStructBytes);

                TpmStructureBase bb = (TpmStructureBase)mx.Get(info.InStructType, "");

                // If a new type is contained, save this command for testing in
                // TestDispatcherCoverage.
                if (HasNewTypes(bb))
                {
                    ExecutedCommandInfo.Add(inBuf);
                }
            }
            else
#else
            if (maskedError != TpmRc.Success)
#endif
            {
                // If a command failed, we can get here only if the corresponding
                // expected error assertion was specified.
                ++NumAsserts;
            }
            ReportProgress();

            // output TPM IO to a text file for later processing
            if (Logger.LogTpmIo)
            {
                while (TpmIoWriter == null)
                {
                    try
                    {
                        string ioLogPath;
                        if (Logger.LogPath != null)
                        {
                            ioLogPath = System.IO.Path.Combine(Logger.LogPath, "tpm_io.txt");
                        }
                        else
                        {
                            string fileName;
                            lock (this)
                            {
                                fileName = "tpm_io-" + DateTime.Now.ToString("yyyy-MMM-dd-HH");
                                if (PrevLogName == fileName)
                                {
                                    fileName += "(" + ++PrevLogInstance + ")";
                                }
                                else
                                {
                                    PrevLogName     = fileName;
                                    PrevLogInstance = 1;
                                }
                            }
                            fileName += ".txt";

#if TSS_MIN_API
                            ioLogPath = fileName;
#else
                            string docsPath = Environment.GetFolderPath(
                                Environment.SpecialFolder.MyDocuments);
                            ioLogPath = System.IO.Path.Combine(docsPath, fileName);
#endif
                        }

                        TpmIoWriter = new StreamWriter(new FileStream(ioLogPath,
                                                                      FileMode.Create));
                        Logger.WriteToLog("Dumping TPM I/O to " + ioLogPath);
                    }
                    catch (Exception e)
                    {
                        string message = "Failed to open the tpm_io.txt file for writing.\n" +
                                         "Error: " + e.Message;
                        Logger.WriteErrorToLog(message);
                    }
                }

                // get the test source code line that initiated the command
                string caller = "unknown";
#if !TSS_NO_STACK
                StackTrace   trace      = new StackTrace(true);
                StackFrame[] frames     = trace.GetFrames();
                int          frameCount = frames.Length;
                StackFrame   f          = null;
                // start at 1 to not count the currently executing function
                for (int j = 1; j < frameCount; j++)
                {
                    f = frames[j];
                    if (f.GetMethod().DeclaringType.Assembly == Logger.TestAssembly)
                    {
                        caller = f.GetFileName() + ":" + f.GetFileLineNumber();
                        break;
                    }
                }
#endif
                string commandCodeString = Enum.GetName(typeof(TpmCc), commandCode);
                string inString          = "{MALFORMED COMMAND BUFFER}";
                string outString         = "{MALFORMED RESPONSE BUFFER}";

                try { inString = CommandProcessor.ParseCommand(inBuf); }
                catch (Exception) { }
                try { outString = CommandProcessor.ParseResponse(commandCodeString, outBuf); }
                catch (Exception) { }

                lock (this)
                {
                    TpmIoWriter.WriteLine(commandCode);
                    TpmIoWriter.WriteLine(caller);

                    TpmIoWriter.WriteLine(">>>> Raw input");
                    TpmIoWriter.WriteLine(Globs.HexFromByteArray(inBuf));
                    TpmIoWriter.WriteLine(">>>> Raw output");
                    TpmIoWriter.WriteLine(Globs.HexFromByteArray(outBuf));

                    TpmIoWriter.WriteLine(">>>> Parsed input");
                    TpmIoWriter.WriteLine(inString);
                    TpmIoWriter.WriteLine(">>>> Parsed output");
                    TpmIoWriter.WriteLine(outString);

                    TpmIoWriter.WriteLine("-----------------------------------------");
                    TpmIoWriter.Flush();
                }
            }

            if (ChainedCallbacks != null)
            {
                ChainedCallbacks.PostCallback(inBuf, outBuf);
            }
        } // ICommandCallbacks.PostCallback
Пример #13
0
 internal override void ToHost(Marshaller m)
 {
     var id = (TpmAlgId)m.Get(typeof (TpmAlgId), "HashAlg");
     if (id == TpmAlgId.Null)
     {
         _HashAlg = id;
         HashData = new byte[0];
         return;
     }
     _HashAlg = id;
     int hashLength = CryptoLib.DigestSize(id);
     HashData = m.GetArray<byte>(hashLength, "HashData");
 }
Пример #14
0
 internal override void ToHost(Marshaller m)
 {
     Algorithm = (TpmAlgId)m.Get(typeof (TpmAlgId), "algorithm");
     if (Algorithm == TpmAlgId.None || Algorithm == TpmAlgId.Null)
     {
         return;
     }
     KeyBits = (ushort)m.Get(typeof (ushort), "keyBits");
     Mode = (TpmAlgId)m.Get(typeof (TpmAlgId), "mode");
 }
Пример #15
0
 internal override void ToHost(Marshaller m)
 {
     Algorithm = m.Get<TpmAlgId>();
     switch (Algorithm)
     {
         case TpmAlgId.None:
         case TpmAlgId.Null:
             return;
         case TpmAlgId.Xor:
             KeyBits = 0;
             Mode = m.Get<TpmAlgId>();
             break;
         case TpmAlgId.Aes:
             KeyBits = m.Get<ushort>();
             Mode = m.Get<TpmAlgId>();
             break;
         default:
             throw new NotImplementedException();
     }
 }
Пример #16
0
 internal override void ToHost(Marshaller m)
 {
     Algorithm = m.Get<TpmAlgId>();
     switch (Algorithm)
     {
         case TpmAlgId.None:
         case TpmAlgId.Null:
             return;
         case TpmAlgId.Xor:
             KeyBits = 0;
             Mode = m.Get<TpmAlgId>();
             break;
         case TpmAlgId.Aes:
             KeyBits = m.Get<ushort>();
             Mode = m.Get<TpmAlgId>();
             break;
         default:
             Globs.Throw<NotImplementedException>("SymDef.ToHost: Unknown algorithm");
             break;
     }
 }