ms-iot / azure-client-tools

Azure Client Tools
Other
43 stars 37 forks source link

TPM Provisioning in Production #39

Closed mburumaxwell closed 5 years ago

mburumaxwell commented 5 years ago

Hi,

It is recommended to use a TPM in device provisioning for because of its security benefits. However, I have noticed that Limpet.exe which is used for TPM operations requires access to PowerShell (a remote session), at least once, to get the enrollment info limpet.exe -azuredps -enrollmentinfo required for the device provisioning service.

I have found that getting a remote PowerShell session to the device requires the IOT_TOOLKIT feature (see https://docs.microsoft.com/en-us/windows-hardware/manufacture/iot/iot-core-feature-list) which is not recommended for Retail Image. If you are deploying to a fresh device from the factory, what would you advise to be the process to get enrollment info?

Thanks in advance

gmileka commented 5 years ago

Hi mburumaxwell,

One way to solve this problem is to write an application (Out-Of-Box, or OOB) that runs on the device, extracts the TPM information and communicates it to the outside world.

The OOB app will be something that runs only once... or it can be part of another app, however, the "OOB" behavior is executed only once.

To communicate with the outside world, the OOB can:

  1. Encode the information into a QR code that is displayed on the screen. The QR code can then be scanned by a companion application on a phone or webcam. The companion application can then enroll the device into DPS.

  2. Use blue tooth to pair the device with a companion application on a phone or a webcam. This is even faster for provisioning than the QR option if data can be exchanged in both directions by the devices. Also, this option has the advantage of not required a screen.

  3. Have the OOB write the information to a USB stick that can then be transferred to another computer where enrollment is created.

thanks, george

leesiyuan commented 5 years ago

Hi, I have an associate question, I also want to use TPM Provisioning in Retail Image, but I can't get the sTPM well installed. In the Windows Device Portal, every time I try to install Software TPM Emulator, my Raspberry Pi reboot and show No TPM installed. I also tried PowerShell command Limpet.exe -azuredps –enrollmentinfo and i got a result like:

<?xml version="1.0" encoding="utf-8"?>
<TpmInfo>TpmNotSupported</TpmInfo>

The TPM works fine in Test Image but even I use the same Features for the Retail image, I can’t use the TPM. So how could I use the sTPM in a Retail image? Thanks!

gmileka commented 5 years ago

@leesiyuan - I've created a new issue to track your question here.

mburumaxwell commented 5 years ago

Hi @gmileka , Thanks for the suggested solutions.

Thanks for your help and ideas

mburumaxwell commented 5 years ago

When I created the issue, my main concern was the lack of PowerShell when omitting IOT_TOOLKIT feature. After further research and about 30 trials, I found that it is allowed to include PowerShell independently with FeatureID: IOT_POWERSHELL. Unfortunately, the device will not show up on the Windows IoT Core Dashboard (this requires IOT_TOOLKIT).

However, once the device connects to a known WiFi network, one can find the IP address of the device (e.g. from the router) and initiate a remote PowerShell session. A custom script can then be used/written to extract the details from the remote device into the developer machine.

Just in case someone else is stuck with the same problem, here is the script:

Param(
    # The name of the computer or its ip address
    [Parameter(Mandatory=$true)]
    [string]
    $ComputerName,

    # The password for the remote computer
    [string]
    $Destination = "$([Environment]::GetFolderPath('Desktop'))",

    # The username for the remote computer
    [string]
    $Username = "Administrator",

    # The password for the remote computer
    [string]
    $Pass = "p@ssw0rd"
)

# start the WinRM service on your desktop to enable remote connections
Write-Host "Starting WinRM service (if not already running)..."
Start-Service -Name "WinRM"

# # add the computer name to trusted hosts so that we can connect to it
# Write-Host "Adding $ComputerName to trusted hosts"
# Set-Item WSMan:\localhost\Client\TrustedHosts -Value $ComputerName -Confirm:$false -Force

# start remote session, with the credentials is provided
Write-Host "Creating new remote session ..."
$FullUser = "$ComputerName\$Username"
$SecurePass = ConvertTo-SecureString $Pass -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential $FullUser, $SecurePass
$RemoteSession = New-PSSession -ComputerName $ComputerName -Credential $Credential
If (!$RemoteSession)
{
    Write-Host "Creating new remote session failed!"
    exit 1
}

# prepare script to execute on remote device
$RemoteScriptBlock = {
    $enrollmentInfoJsonRaw = limpet -azuredps -enrollmentinfo -json
    $enrollmentInfoJson = [string]::Join("", $enrollmentInfoJsonRaw) -replace "\s", ""
    $enrollmentInfoJson
}

# execute script block in the remote session and get the results
Write-Host "Executing script in remote session ..."
$RemoteEnrollmentInfo = Invoke-Command -Session $remoteSession -ScriptBlock $RemoteScriptBlock
If (!$RemoteEnrollmentInfo)
{
    Write-Host "Executing script in remote session failed!"
    exit 1
}

# exit the remote session
Write-Host "Disconnecting remote session ..."
$RemoteSession = Disconnect-PSSession -Session $RemoteSession
If (!$RemoteSession)
{
    Write-Host "Disconnecting remote session failed!"
    exit 1
}

# write enrollment information to a file
$Object = $null
$DestinationPath = "$Destination\enrollmentinfo.json"
If (Test-Path -Path $DestinationPath)
{
    $Object = Set-Content -Path $DestinationPath -Value $RemoteEnrollmentInfo -PassThru
}
else
{
    $Object = New-Item -Path $DestinationPath -Value $RemoteEnrollmentInfo -Type File -Force
}

If ($Object)
{
    Write-Host "Enrollment information written to $DestinationPath"
}
else
{
    # print out a warning and the enrollment information
    Write-Host "Writing enrollment information to '$DestinationPath' failed!. Please do it manually with the information below ..."
    Write-Host $RemoteEnrollmentInfo
}

Write-Host "Completed!"

To execute this script

.\EnrollRemoteDevice.ps1 -ComputerName 192.168.x.x -Pass "customPassword"