diff --git a/provisioning/Samples/device/Common/ProvisioningDeviceClientSample.cs b/provisioning/Samples/device/Common/ProvisioningDeviceClientSample.cs
deleted file mode 100644
index 9548990b..00000000
--- a/provisioning/Samples/device/Common/ProvisioningDeviceClientSample.cs
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-using Microsoft.Azure.Devices.Client;
-using Microsoft.Azure.Devices.Provisioning.Client;
-using Microsoft.Azure.Devices.Shared;
-using System;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-
-namespace Microsoft.Azure.Devices.Provisioning.Client.Samples
-{
- public class ProvisioningDeviceClientSample
- {
- ProvisioningDeviceClient _provClient;
- SecurityProvider _security;
-
- public ProvisioningDeviceClientSample(ProvisioningDeviceClient provisioningDeviceClient, SecurityProvider security)
- {
- _provClient = provisioningDeviceClient;
- _security = security;
- }
-
- public async Task RunSampleAsync()
- {
- Console.WriteLine($"RegistrationID = {_security.GetRegistrationID()}");
- VerifyRegistrationIdFormat(_security.GetRegistrationID());
-
- Console.Write("ProvisioningClient RegisterAsync . . . ");
- DeviceRegistrationResult result = await _provClient.RegisterAsync().ConfigureAwait(false);
-
- Console.WriteLine($"{result.Status}");
- Console.WriteLine($"ProvisioningClient AssignedHub: {result.AssignedHub}; DeviceID: {result.DeviceId}");
-
- if (result.Status != ProvisioningRegistrationStatusType.Assigned) return;
-
- IAuthenticationMethod auth;
- if (_security is SecurityProviderTpm)
- {
- Console.WriteLine("Creating TPM DeviceClient authentication.");
- auth = new DeviceAuthenticationWithTpm(result.DeviceId, _security as SecurityProviderTpm);
- }
- else if (_security is SecurityProviderX509)
- {
- Console.WriteLine("Creating X509 DeviceClient authentication.");
- auth = new DeviceAuthenticationWithX509Certificate(result.DeviceId, (_security as SecurityProviderX509).GetAuthenticationCertificate());
- }
- else if (_security is SecurityProviderSymmetricKey)
- {
- Console.WriteLine("Creating Symmetric Key DeviceClient authenication");
- auth = new DeviceAuthenticationWithRegistrySymmetricKey(result.DeviceId, (_security as SecurityProviderSymmetricKey).GetPrimaryKey());
- }
- else
- {
- throw new NotSupportedException("Unknown authentication type.");
- }
-
- using (DeviceClient iotClient = DeviceClient.Create(result.AssignedHub, auth, TransportType.Amqp))
- {
- Console.WriteLine("DeviceClient OpenAsync.");
- await iotClient.OpenAsync().ConfigureAwait(false);
- Console.WriteLine("DeviceClient SendEventAsync.");
- await iotClient.SendEventAsync(new Message(Encoding.UTF8.GetBytes("TestMessage"))).ConfigureAwait(false);
- Console.WriteLine("DeviceClient CloseAsync.");
- await iotClient.CloseAsync().ConfigureAwait(false);
- }
- }
-
- private void VerifyRegistrationIdFormat(string v)
- {
- var r = new Regex("^[a-z0-9-]*$");
- if (!r.IsMatch(v))
- {
- throw new FormatException("Invalid registrationId: The registration ID is alphanumeric, lowercase, and may contain hyphens");
- }
- }
- }
-}
diff --git a/provisioning/Samples/device/SymmetricKeySample/ProvisioningDeviceClientSample.cs b/provisioning/Samples/device/SymmetricKeySample/ProvisioningDeviceClientSample.cs
index c6b0a6a2..f4580c9f 100644
--- a/provisioning/Samples/device/SymmetricKeySample/ProvisioningDeviceClientSample.cs
+++ b/provisioning/Samples/device/SymmetricKeySample/ProvisioningDeviceClientSample.cs
@@ -53,9 +53,9 @@ public async Task RunSampleAsync()
security,
transportHandler);
- Console.WriteLine($"Initialized for registration Id {security.GetRegistrationID()}");
+ Console.WriteLine($"Initialized for registration Id {security.GetRegistrationID()}.");
- Console.WriteLine("Registering with the device provisioning service... ");
+ Console.WriteLine("Registering with the device provisioning service...");
DeviceRegistrationResult result = await provClient.RegisterAsync();
Console.WriteLine($"Registration status: {result.Status}.");
diff --git a/provisioning/Samples/device/TpmSample/Parameters.cs b/provisioning/Samples/device/TpmSample/Parameters.cs
new file mode 100644
index 00000000..b6b43e59
--- /dev/null
+++ b/provisioning/Samples/device/TpmSample/Parameters.cs
@@ -0,0 +1,52 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using CommandLine;
+using Microsoft.Azure.Devices.Client;
+
+namespace Microsoft.Azure.Devices.Provisioning.Client.Samples
+{
+ ///
+ /// Parameters for the application
+ ///
+ internal class Parameters
+ {
+ [Option(
+ 'e',
+ "GetTpmEndorsementKey",
+ HelpText = "Gets the TPM endorsement key. Use this option by itself to get the EK needed to create a DPS individual enrollment.")]
+ public bool GetTpmEndorsementKey { get; set; }
+
+ [Option(
+ 'u',
+ "UseTpmSimulator",
+ HelpText = "Runs the TPM simulator - useful when the local device does not have a TPM chip.")]
+ public bool UseTpmSimulator { get; set; }
+
+ [Option(
+ 's',
+ "IdScope",
+ HelpText = "The Id Scope of the DPS instance. For normal runs, this is required.")]
+ public string IdScope { get; set; }
+
+ [Option(
+ 'r',
+ "RegistrationId",
+ HelpText = "The registration Id from the individual enrollment. For normal runs, this is required.")]
+ public string RegistrationId { get; set; }
+
+ [Option(
+ 'g',
+ "GlobalDeviceEndpoint",
+ Default = "global.azure-devices-provisioning.net",
+ HelpText = "The global endpoint for devices to connect to.")]
+ public string GlobalDeviceEndpoint { get; set; }
+
+ [Option(
+ 't',
+ "TransportType",
+ Default = TransportType.Amqp,
+ HelpText = "The transport to use to communicate with the device provisioning instance. Possible values include Amqp, Amqp_WebSocket_Only, Amqp_Tcp_only, and Http1.")]
+ public TransportType TransportType { get; set; }
+ }
+}
diff --git a/provisioning/Samples/device/TpmSample/Program.cs b/provisioning/Samples/device/TpmSample/Program.cs
index 3a6936d2..17573e9c 100644
--- a/provisioning/Samples/device/TpmSample/Program.cs
+++ b/provisioning/Samples/device/TpmSample/Program.cs
@@ -1,76 +1,64 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using Microsoft.Azure.Devices.Provisioning.Client;
-using Microsoft.Azure.Devices.Provisioning.Client.Transport;
+using CommandLine;
+using Microsoft.Azure.Devices.Provisioning.Security;
using Microsoft.Azure.Devices.Provisioning.Security.Samples;
-using Microsoft.Azure.Devices.Shared;
using System;
+using System.Threading.Tasks;
namespace Microsoft.Azure.Devices.Provisioning.Client.Samples
{
+ ///
+ /// A sample to illustrate connecting a device to hub using the device provisioning service and a certificate.
+ ///
public static class Program
{
- // The Provisioning Hub IDScope.
-
- // For this sample either:
- // - pass this value as a command-prompt argument
- // - set the DPS_IDSCOPE environment variable
- // - create a launchSettings.json (see launchSettings.json.template) containing the variable
- private static string s_idScope = Environment.GetEnvironmentVariable("DPS_IDSCOPE");
-
- private const string RegistrationId = "testtpmregistration1";
- private const string GlobalDeviceEndpoint = "global.azure-devices-provisioning.net";
-
- public static int Main(string[] args)
+ public static async Task Main(string[] args)
{
- if (string.IsNullOrWhiteSpace(s_idScope) && (args.Length > 0))
- {
- s_idScope = args[0];
- }
-
- if (string.IsNullOrWhiteSpace(s_idScope))
- {
- Console.WriteLine("ProvisioningDeviceClientTpm ");
- return 1;
- }
-
- // Remove if a real TPM is being used.
- Console.WriteLine("Starting TPM simulator.");
- SecurityProviderTpmSimulator.StartSimulatorProcess();
-
- // Replace the following type with SecurityProviderTpmHsm() to use a real TPM2.0 device.
- using (var security = new SecurityProviderTpmSimulator(RegistrationId))
+ // Parse application parameters
+ Parameters parameters = null;
+ ParserResult result = Parser.Default.ParseArguments(args)
+ .WithParsed(parsedParams =>
+ {
+ parameters = parsedParams;
+ })
+ .WithNotParsed(errors =>
+ {
+ Environment.Exit(1);
+ });
- // Select one of the available transports:
- // To optimize for size, reference only the protocols used by your application.
- using (var transport = new ProvisioningTransportHandlerHttp())
- // using (var transport = new ProvisioningTransportHandlerAmqp(TransportFallbackType.TcpOnly))
- // using (var transport = new ProvisioningTransportHandlerAmqp(TransportFallbackType.WebSocketOnly))
+ // This sample provides a way to get the endorsement key (EK) required in creation of the individual enrollment
+ if (parameters.GetTpmEndorsementKey)
{
- // Note that the TPM simulator will create an NVChip file containing the simulated TPM state.
- Console.WriteLine("Extracting endorsement key.");
- string base64EK = Convert.ToBase64String(security.GetEndorsementKey());
+ if (parameters.UseTpmSimulator)
+ {
+ Console.WriteLine("Starting TPM simulator...");
+ SecurityProviderTpmSimulator.StartSimulatorProcess();
+ }
- Console.WriteLine(
- "In your Azure Device Provisioning Service please go to 'Manage enrollments' and select " +
- "'Individual Enrollments'. Select 'Add' then fill in the following:");
+ using var security = new SecurityProviderTpmHsm(null);
+ Console.WriteLine($"Your EK is {Convert.ToBase64String(security.GetEndorsementKey())}");
- Console.WriteLine("\tMechanism: TPM");
- Console.WriteLine($"\tRegistration ID: {RegistrationId}");
- Console.WriteLine($"\tEndorsement key: {base64EK}");
- Console.WriteLine("\tDevice ID: iothubtpmdevice1 (or any other valid DeviceID)");
- Console.WriteLine();
- Console.WriteLine("Press ENTER when ready.");
- Console.ReadLine();
+ if (parameters.UseTpmSimulator)
+ {
+ SecurityProviderTpmSimulator.StopSimulatorProcess();
+ }
- ProvisioningDeviceClient provClient =
- ProvisioningDeviceClient.Create(GlobalDeviceEndpoint, s_idScope, security, transport);
+ return 0;
+ }
- var sample = new ProvisioningDeviceClientSample(provClient, security);
- sample.RunSampleAsync().GetAwaiter().GetResult();
+ // For a normal run of this sample, IdScope and RegistrationId are required
+ if (string.IsNullOrWhiteSpace(parameters.IdScope)
+ || string.IsNullOrWhiteSpace(parameters.RegistrationId))
+ {
+ Console.WriteLine(CommandLine.Text.HelpText.AutoBuild(result, null, null));
+ Environment.Exit(1);
}
+ var sample = new ProvisioningDeviceClientSample(parameters);
+ await sample.RunSampleAsync();
+
return 0;
}
}
diff --git a/provisioning/Samples/device/TpmSample/ProvisioningDeviceClientSample.cs b/provisioning/Samples/device/TpmSample/ProvisioningDeviceClientSample.cs
new file mode 100644
index 00000000..5036ff34
--- /dev/null
+++ b/provisioning/Samples/device/TpmSample/ProvisioningDeviceClientSample.cs
@@ -0,0 +1,107 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using Microsoft.Azure.Devices.Client;
+using Microsoft.Azure.Devices.Provisioning.Client.Transport;
+using Microsoft.Azure.Devices.Provisioning.Security;
+using Microsoft.Azure.Devices.Provisioning.Security.Samples;
+using Microsoft.Azure.Devices.Shared;
+using System;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Microsoft.Azure.Devices.Provisioning.Client.Samples
+{
+ ///
+ /// Demonstrates how to register a device with the device provisioning service using a certificate, and then
+ /// use the registration information to authenticate to IoT Hub.
+ ///
+ internal class ProvisioningDeviceClientSample
+ {
+ private readonly Parameters _parameters;
+
+ public ProvisioningDeviceClientSample(Parameters parameters)
+ {
+ _parameters = parameters;
+ }
+
+ public async Task RunSampleAsync()
+ {
+ SecurityProviderTpm security = null;
+
+ try
+ {
+ if (_parameters.UseTpmSimulator)
+ {
+ Console.WriteLine("Starting TPM simulator...");
+ SecurityProviderTpmSimulator.StartSimulatorProcess();
+ security = new SecurityProviderTpmSimulator(_parameters.RegistrationId);
+ }
+ else
+ {
+ Console.WriteLine("Initializing security using the local TPM...");
+ security = new SecurityProviderTpmHsm(_parameters.RegistrationId);
+ }
+
+ Console.WriteLine($"Initializing the device provisioning client...");
+
+ using var transport = GetTransportHandler();
+ ProvisioningDeviceClient provClient = ProvisioningDeviceClient.Create(
+ _parameters.GlobalDeviceEndpoint,
+ _parameters.IdScope,
+ security,
+ transport);
+
+ Console.WriteLine($"Initialized for registration Id {security.GetRegistrationID()}.");
+
+ Console.WriteLine("Registering with the device provisioning service... ");
+ DeviceRegistrationResult result = await provClient.RegisterAsync();
+
+ Console.WriteLine($"Registration status: {result.Status}.");
+ if (result.Status != ProvisioningRegistrationStatusType.Assigned)
+ {
+ Console.WriteLine($"Registration status did not assign a hub, so exiting this sample.");
+ return;
+ }
+
+ Console.WriteLine($"Device {result.DeviceId} registered to {result.AssignedHub}.");
+
+ Console.WriteLine("Creating TPM authentication for IoT Hub...");
+ IAuthenticationMethod auth = new DeviceAuthenticationWithTpm(result.DeviceId, security);
+
+ Console.WriteLine($"Testing the provisioned device with IoT Hub...");
+ using DeviceClient iotClient = DeviceClient.Create(result.AssignedHub, auth, _parameters.TransportType);
+
+ Console.WriteLine("Sending a telemetry message...");
+ using var message = new Message(Encoding.UTF8.GetBytes("TestMessage"));
+ await iotClient.SendEventAsync(message);
+ }
+ finally
+ {
+ if (_parameters.UseTpmSimulator)
+ {
+ SecurityProviderTpmSimulator.StopSimulatorProcess();
+ }
+
+ security?.Dispose();
+ }
+
+ Console.WriteLine("Finished.");
+ }
+
+ private ProvisioningTransportHandler GetTransportHandler()
+ {
+ return _parameters.TransportType switch
+ {
+ TransportType.Amqp => new ProvisioningTransportHandlerAmqp(),
+ TransportType.Amqp_Tcp_Only => new ProvisioningTransportHandlerAmqp(TransportFallbackType.WebSocketOnly),
+ TransportType.Amqp_WebSocket_Only => new ProvisioningTransportHandlerAmqp(TransportFallbackType.TcpOnly),
+ TransportType.Http1 => new ProvisioningTransportHandlerHttp(),
+ TransportType.Mqtt => throw new NotSupportedException("MQTT is not supported for TPM"),
+ TransportType.Mqtt_Tcp_Only => throw new NotSupportedException("MQTT is not supported for TPM"),
+ TransportType.Mqtt_WebSocket_Only => throw new NotSupportedException("MQTT is not supported for TPM"),
+ _ => throw new NotSupportedException($"Unsupported transport type {_parameters.TransportType}"),
+ };
+ }
+ }
+}
diff --git a/provisioning/Samples/device/TpmSample/TpmSample.csproj b/provisioning/Samples/device/TpmSample/TpmSample.csproj
index bb1ee635..bc1776c6 100644
--- a/provisioning/Samples/device/TpmSample/TpmSample.csproj
+++ b/provisioning/Samples/device/TpmSample/TpmSample.csproj
@@ -8,17 +8,15 @@
-
-
-
-
+
-
+
-
+
+
diff --git a/provisioning/Samples/device/TpmSample/readme.md b/provisioning/Samples/device/TpmSample/readme.md
index 0b265ea7..b88c2bca 100644
--- a/provisioning/Samples/device/TpmSample/readme.md
+++ b/provisioning/Samples/device/TpmSample/readme.md
@@ -6,13 +6,19 @@ This is a quick tutorial with the steps to register a device in the Microsoft Az
## How to run the sample
-Ensure that all prerequisite steps presented in [samples](../) have been performed.
-To run the sample, in a developer command prompt enter:
+1. Ensure that all prerequisite steps presented in [samples](../) have been performed.
+1. The sample must be run in administrative mode, so open VS as an admin, or open a console window as an admin.
+1. You'll need the endorsement key (EK) of your TPM device to create an individual enrollment. This sample has a parameter `--GetTpmEndorsementKey` that can be used to get it and print it to the console.
+1. If using a console, enter: `dotnet run -s -r `.
+1. If using VS, edit project properties | debug | application arguments and add the parameters: `-s -r `
-`dotnet run `
-
-replacing `IDScope` with the value found within the Device Provisioning Service Overview tab. E.g. `dotnet run 0ne1234ABCD`
+> Replace `IdScope` with the value found within the Device Provisioning Service Overview tab, and `RegistrationId` with the individual enrollment registration Id.
+> To see a full list of parameters, run `dotnet run -?`.
Continue by following the instructions presented by the sample.
-The sample is currently using `SecurityProviderTpmSimulator` which is not supported on Linux. To run against a real TPM2.0 device, replace this with `SecurityProviderTpm`.
+## Notes
+
+For convenience, this sample uses a TPM simulator (SecurityProviderTpmSimulator) which is not supported on Linux.
+
+To run against a real TPM2.0 device, replace this with `SecurityProviderTpmHsm`.
diff --git a/provisioning/Samples/device/X509Sample/ProvisioningDeviceClientSample.cs b/provisioning/Samples/device/X509Sample/ProvisioningDeviceClientSample.cs
index cd25d85a..4cee40c7 100644
--- a/provisioning/Samples/device/X509Sample/ProvisioningDeviceClientSample.cs
+++ b/provisioning/Samples/device/X509Sample/ProvisioningDeviceClientSample.cs
@@ -40,7 +40,7 @@ public async Task RunSampleAsync()
security,
transport);
- Console.WriteLine($"Initialized for registration Id {security.GetRegistrationID()}");
+ Console.WriteLine($"Initialized for registration Id {security.GetRegistrationID()}.");
Console.WriteLine("Registering with the device provisioning service... ");
DeviceRegistrationResult result = await provClient.RegisterAsync();
diff --git a/provisioning/Samples/device/X509Sample/readme.md b/provisioning/Samples/device/X509Sample/readme.md
index 7ff42cfd..d3b18a15 100644
--- a/provisioning/Samples/device/X509Sample/readme.md
+++ b/provisioning/Samples/device/X509Sample/readme.md
@@ -25,7 +25,7 @@ Certificate: Select the public key 'certificate.cer' file.
To run the sample, in a developer command prompt enter: `dotnet run -s `
-> Replace `IdScope` with the value found within the Device Provisioning Service Overview tab. E.g. `dotnet run 0ne1234ABCD`
+> Replace `IdScope` with the value found within the Device Provisioning Service Overview tab.
> To see a full list of parameters, run `dotnet run -?`.
Continue by following the instructions presented in the sample console window.
diff --git a/provisioning/Samples/device/readme.md b/provisioning/Samples/device/readme.md
index d2b134df..351ca859 100644
--- a/provisioning/Samples/device/readme.md
+++ b/provisioning/Samples/device/readme.md
@@ -6,33 +6,26 @@ This folder contains samples demonstrating the steps required to dynamically ass
To ensure that only authorized devices can be provisioned, two device attestation mechanisms are supported by the service: one based on X.509 certificates and another based on Trusted Platform Module (TPM) devices. In both cases, public/private key authentication will be performed during provisioning.
-_Preview only:_ The SDK currently supports two communication protocols: HTTP and AMQP over TLS.
-
## Device provisioning in a nutshell
Provisioning is achieved by using a single call to the `ProvisioningDeviceClient.RegisterAsync()` API specifying the `GlobalDeviceEndpoint`, the IDScope (unique for each Provisioning Service deployment), a `SecurityProvider` and a `ProvisioningTransportHandler`:
```C#
- ProvisioningDeviceClient provClient = ProvisioningDeviceClient.Create(globalDeviceEndpoint, s_idScope, security, transport);
- DeviceRegistrationResult result = await provClient.RegisterAsync();
- if (result.Status != ProvisioningRegistrationStatusType.Assigned)
- {
- Console.WriteLine($"ProvisioningClient AssignedHub: {result.AssignedHub}; DeviceID: {result.DeviceId}");
- }
+ProvisioningDeviceClient provClient = ProvisioningDeviceClient.Create(globalDeviceEndpoint, s_idScope, security, transport);
+DeviceRegistrationResult result = await provClient.RegisterAsync();
+if (result.Status != ProvisioningRegistrationStatusType.Assigned)
+{
+ Console.WriteLine($"ProvisioningClient AssignedHub: {result.AssignedHub}; DeviceId: {result.DeviceId}");
+}
```
-To change the transport between AMQP, HTTP and MQTT change the following line:
-```C#
- using (var transport = new ProvisioningTransportHandlerHttp())
- using (var transport = new ProvisioningTransportHandlerAmqp())
- using (var transport = new ProvisioningTransportHandlerMqtt())
-```
+To change the transport between AMQP, HTTP and MQTT, check the sample parameters (`-h`).
### Provisioning devices using X.509 certificate-based attestation
Devices must have access to a single certificate with a private key. The private key can be hidden from the application using PKCS #11 Hardware Security Modules.
-When Group Enrollment is used, both the _RegistrationID_ as well as the _DeviceID_ will be equal to the Common Name portion of the certificate Subject. (e.g. If the subject is `CN=mydevice O=Contoso C=US`, the RegistrationID and DeviceID will be `mydevice`.) The name must respect the [DeviceID naming constraints](https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-identity-registry).
+When Group Enrollment is used, both the _RegistrationID_ as well as the _DeviceId_ will be equal to the Common Name portion of the certificate Subject. (e.g. If the subject is `CN=mydevice O=Contoso C=US`, the RegistrationID and DeviceId will be `mydevice`.) The name must respect the [DeviceId naming constraints](https://docs.microsoft.com/azure/iot-hub/iot-hub-devguide-identity-registry).
X.509 attestation comes in two flavors:
@@ -51,29 +44,24 @@ _Note:_ the device certificate can also be a signing certificate of the actual c
An example of specifying the authentication X509Certificate using a PKCS12 PFX password-protected file:
```C#
- using (var certificate = new X509Certificate2(s_certificateFileName, certificatePassword))
- using (var security = new SecurityProviderX509Certificate(certificate))
- {
- // ... (see sample for details)
- }
+using var certificate = new X509Certificate2(s_certificateFileName, certificatePassword);
+using var security = new SecurityProviderX509Certificate(certificate);
+// ... (see sample for details)
```
-The SDK provides an extension model [SecurityProviderX509](https://github.com/Azure/azure-iot-sdk-csharp/blob/master/shared/src/SecurityProviderX509.cs) that allows hardware vendors to implement custom Hardware Security Modules that store the device certificates. On Windows, PKCS11 HSM devices are supported through the [Certificate Store](https://docs.microsoft.com/en-us/windows-hardware/drivers/install/certificate-stores).
+The SDK provides an extension model [SecurityProviderX509](https://github.com/Azure/azure-iot-sdk-csharp/blob/master/shared/src/SecurityProviderX509.cs) that allows hardware vendors to implement custom Hardware Security Modules that store the device certificates. On Windows, PKCS11 HSM devices are supported through the [Certificate Store](https://docs.microsoft.com/windows-hardware/drivers/install/certificate-stores).
An example of implementation for this extension module is the [SecurityProviderX509Certificate](https://github.com/Azure/azure-iot-sdk-csharp/blob/master/shared/src/SecurityProviderX509Certificate.cs) class.
-### Provisioning devices using TPM based attestation
+### Provisioning devices using TPM-based attestation
In the case of TPM attestation, a RegistrationID must be supplied by the application.
-The TPM attestation supports only Individual Enrollments. The [Endorsement Key](https://technet.microsoft.com/en-us/library/cc770443(v=ws.11).aspx) (EK) must be supplied to the service. During provisioning, the [Storage Root Key](https://technet.microsoft.com/en-us/library/cc753560(v=ws.11).aspx) (SRK) will also be used to ensure that TPM ownership changes result in devices provisioned to the correct owner.
-
+The TPM attestation supports only Individual Enrollments. The [Endorsement Key](https://technet.microsoft.com/library/cc770443(v=ws.11).aspx) (EK) must be supplied to the service. During provisioning, the [Storage Root Key](https://technet.microsoft.com/library/cc753560(v=ws.11).aspx) (SRK) will also be used to ensure that TPM ownership changes result in devices provisioned to the correct owner.
```C#
- using (var security = new SecurityProviderTpmSimulator(RegistrationId))
- {
- // ... (see sample for details)
- }
+using var security = new SecurityProviderTpmSimulator(RegistrationId);
+// ... (see sample for details)
```
The SDK provides an extension model [SecurityProviderTpm](https://github.com/Azure/azure-iot-sdk-csharp/blob/master/shared/src/SecurityProviderTpm.cs) that allows hardware vendors to implement custom TPM v2.0 Hardware Security Modules.
@@ -88,13 +76,11 @@ The samples use a TPMv2.0 simulator that uses a loopback TCP connection for comm
### How to run the samples
1. Prepare your development environment. Follow the instructions at ./doc/devbox_setup.md
+1. Setup your IoT Hub Device Provisioning Service and associated IoT Hub. Follow the instructions at .
+1. Continue following specific instructions in each of the sample folders.
-2. Setup your IoT Hub Device Provisioning Service and associated IoT Hub. Follow the instructions at https://docs.microsoft.com/en-us/azure/iot-dps/quick-setup-auto-provision
-
-4. Continue following specific instructions in each of the sample folders.
-
-### Read More
+### Read more
-- [Azure IoT Hub Device Provisioning Service (preview) Documentation](https://docs.microsoft.com/en-us/azure/iot-dps/)
+- [Azure IoT Hub Device Provisioning Service (preview) Documentation](https://docs.microsoft.com/azure/iot-dps/)
- [How to use the Azure IoT SDKs for .NET](https://github.com/azure/azure-iot-sdk-csharp#how-to-use-the-azure-iot-sdks-for-net)
diff --git a/security/Samples/SecurityProviderTpmSimulator/.gitignore b/security/Samples/SecurityProviderTpmSimulator/.gitignore
new file mode 100644
index 00000000..e94a1012
--- /dev/null
+++ b/security/Samples/SecurityProviderTpmSimulator/.gitignore
@@ -0,0 +1 @@
+NVChip
\ No newline at end of file
diff --git a/security/Samples/SecurityProviderTpmSimulator/SecurityProviderTpmSimulator.cs b/security/Samples/SecurityProviderTpmSimulator/SecurityProviderTpmSimulator.cs
index 0015fb54..12618ee2 100644
--- a/security/Samples/SecurityProviderTpmSimulator/SecurityProviderTpmSimulator.cs
+++ b/security/Samples/SecurityProviderTpmSimulator/SecurityProviderTpmSimulator.cs
@@ -4,7 +4,6 @@
using Microsoft.Azure.Devices.Shared;
using System;
using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
@@ -28,11 +27,14 @@ public class SecurityProviderTpmSimulator : SecurityProviderTpm
private static string s_simulatorExeName;
+ private static int s_simulatorProcessId;
+
private TcpTpmDevice _tcpTpmDevice;
private Tpm2 _tpm2;
private SecurityProviderTpmHsm _innerClient;
- public SecurityProviderTpmSimulator(string registrationId) : base(registrationId)
+ public SecurityProviderTpmSimulator(string registrationId)
+ : base(registrationId)
{
_tcpTpmDevice = new TcpTpmDevice(SimulatorAddress, SimulatorPort);
_tcpTpmDevice.Connect();
@@ -65,17 +67,22 @@ public override byte[] Sign(byte[] data)
}
- [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Sample code resiliency")]
public static void StopSimulatorProcess()
{
- foreach (var process in Process.GetProcessesByName(Path.GetFileNameWithoutExtension(s_simulatorExeName)))
+ if (s_simulatorProcessId != 0)
{
try
{
- process?.Kill();
+ Process process = Process.GetProcessById(s_simulatorProcessId);
+ process.Kill();
+ }
+ catch (ArgumentException)
+ {
+ // Process not found
}
- catch (Exception)
+ finally
{
+ s_simulatorProcessId = 0;
}
}
}
@@ -116,7 +123,7 @@ public static void StartSimulatorProcess()
if (files.Length == 0)
{
- throw new InvalidOperationException($"TPM Simulator not found : {s_simulatorExeName}");
+ throw new InvalidOperationException($"TPM Simulator not found: {s_simulatorExeName}");
}
using var simulatorProcess = new Process
@@ -130,6 +137,7 @@ public static void StartSimulatorProcess()
};
simulatorProcess.Start();
+ s_simulatorProcessId = simulatorProcess.Id;
}
protected override void Dispose(bool disposing)