/*
* Copyright (c) 2021 Microsoft Corporation
*/
using System;
using System.Collections.Generic;
using System.Linq;
using Tpm2Lib;
class Program
{
///
/// Defines the argument to use to have this program use a Linux TPM device
/// file or TPM access broker to communicate with a TPM 2.0 device.
///
/// NOTE: Use this device in order to communicate to the EFLOW VM
///
private const string DeviceLinux = "-tpm0";
///
/// Defines the argument to use to have this program use a TCP connection
/// to communicate with a TPM 2.0 simulator.
///
private const string DeviceSimulator = "-tcp";
///
/// Defines the argument to use to have this program use the Windows TBS
/// API to communicate with a TPM 2.0 device.
/// Use this device if you are testing the TPM Read functionality on the Windows host.
///
private const string DeviceWinTbs = "-tbs";
///
/// The default connection to use for communication with the TPM.
///
private const string DefaultDevice = DeviceLinux;
///
/// If using a TCP connection, the default DNS name/IP address for the
/// simulator.
///
private const string DefaultSimulatorName = "127.0.0.1";
///
/// If using a TCP connection, the default TCP port of the simulator.
///
private const int DefaultSimulatorPort = 2321;
///
/// Prints instructions for usage of this program.
///
static void WriteUsage()
{
Console.WriteLine();
Console.WriteLine("Usage: NV []");
Console.WriteLine();
Console.WriteLine(" can be '{0}' or '{1}' or '{2}'. Defaults to '{3}'.", DeviceLinux, DeviceWinTbs, DeviceSimulator, DefaultDevice);
Console.WriteLine(" If is '{0}', the program will connect to the TPM via\n" +
" the TPM2 Access Broker on the EFLOW VM.", DeviceLinux);
Console.WriteLine(" If is '{0}', the program will connect to a simulator\n" +
" listening on a TCP port.", DeviceSimulator);
Console.WriteLine(" If is '{0}', the program will use the Windows TBS interface to talk\n" +
" to the TPM device (for use on testing within the Windows Host).", DeviceWinTbs);
}
///
/// Parse the arguments of the program and return the selected values.
///
/// The arguments of the program.
/// The name of the selected TPM connection created.
/// True if the arguments could be parsed. False if an unknown argument or malformed
/// argument was present.
static bool ParseArguments(IEnumerable args, out string tpmDeviceName)
{
tpmDeviceName = DefaultDevice;
foreach (string arg in args)
{
if (string.Compare(arg, DeviceSimulator, true) == 0)
{
tpmDeviceName = DeviceSimulator;
}
else if (string.Compare(arg, DeviceWinTbs, true) == 0)
{
tpmDeviceName = DeviceWinTbs;
}
else if (string.Compare(arg, DeviceLinux, true) == 0)
{
tpmDeviceName = DeviceLinux;
}
else
{
return false;
}
}
return true;
}
///
/// After parsing the arguments for the TPM device, the program executes a read
/// of the prior initialized NV index (3001). The program then outputs the 8 bytes
/// previously stored at that index.
///
/// Arguments to this program.
static void Main(string[] args)
{
//
// Parse the program arguments. If the wrong arguments are given or
// are malformed, then instructions for usage are displayed and
// the program terminates.
//
string tpmDeviceName;
if (!ParseArguments(args, out tpmDeviceName))
{
WriteUsage();
return;
}
try
{
Tpm2Device tpmDevice;
switch (tpmDeviceName)
{
case DeviceSimulator:
tpmDevice = new TcpTpmDevice(DefaultSimulatorName, DefaultSimulatorPort);
break;
case DeviceWinTbs:
tpmDevice = new TbsDevice();
break;
case DeviceLinux:
tpmDevice = new LinuxTpmDevice();
break;
default:
throw new Exception("Unknown device selected.");
}
tpmDevice.Connect();
var tpm = new Tpm2(tpmDevice);
if (tpmDevice is TcpTpmDevice)
{
//
// If we are using the simulator, we have to do a few things the
// firmware would usually do. These actions have to occur after
// the connection has been established.
//
tpmDevice.PowerCycle();
tpm.Startup(Su.Clear);
}
NVReadOnly(tpm);
// TPM clean up procedure
tpm.Dispose();
}
catch (Exception e)
{
Console.WriteLine("Exception occurred: {0}", e.Message);
}
Console.WriteLine("Press Any Key to continue.");
Console.ReadLine();
}
///
/// This sample demonstrates the creation and use of TPM NV memory storage.
/// NOTE: Only reads from the TPM NV Memory are supported on the EFLOW VM.
/// In order to properly run through this sample, you must have previously
/// setup and written to NV Index 3001 on the Windows Host. See README.md
/// for details.
///
/// Reference to TPM object.
static void NVReadOnly(Tpm2 tpm)
{
//
// AuthValue encapsulates an authorization value: essentially a byte-array.
// OwnerAuth is the owner authorization value of the TPM-under-test. We
// assume that it (and other) auths are set to the default (null) value.
// If running on a real TPM, which has been provisioned by Windows, this
// value will be different. An administrator can retrieve the owner
// authorization value from the registry.
//
int nvIndex = 3001; // Arbitrarily Chosen
ushort dataLength = 8; // Length from the data stored into the TPM
TpmHandle nvHandle = TpmHandle.NV(nvIndex);
AuthValue nvAuth = new AuthValue(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 });
Console.WriteLine("Reading NVIndex {0}.", nvIndex);
byte[] nvRead = tpm[nvAuth].NvRead(nvHandle, nvHandle, dataLength, 0);
Console.WriteLine("Read Bytes: {0}", BitConverter.ToString(nvRead));
}
}