Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions AADDeviceTrust.Client/Private/Get-AzureADDeviceID.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ function Get-AzureADDeviceID {
Author: Nickolaj Andersen
Contact: @NickolajA
Created: 2021-05-26
Updated: 2021-05-26
Updated: 2023-06-20

Version history:
1.0.0 - (2021-05-26) Function created
1.0.1 - (2022-10-20) @AzureToTheMax - Fixed issue pertaining to Cloud PCs (Windows 365) devices ability to locate their AzureADDeviceID.
1.0.2 - (2023-06-20) @AzureToTheMax - Fixed issue pertaining to Cloud PCs (Windows 365) devices where the reported AzureADDeviceID was in all capitals, breaking signature creation.

#>
Process {
# Define Cloud Domain Join information registry path
Expand All @@ -27,10 +30,34 @@ function Get-AzureADDeviceID {
if ($AzureADJoinCertificate -ne $null) {
# Determine the device identifier from the subject name
$AzureADDeviceID = ($AzureADJoinCertificate | Select-Object -ExpandProperty "Subject") -replace "CN=", ""
# Convert upper to lowercase.
$AzureADDeviceID = "$($AzureADDeviceID)".ToLower()

# Handle return value
return $AzureADDeviceID

} else {

#If no certificate was found, locate it by Common Name instead of Thumbprint. This is likely a CPC or similar.
$AzureADJoinCertificate = Get-ChildItem -Path "Cert:\LocalMachine\My" -Recurse | Where-Object { $PSItem.Subject -like "CN=($AzureADJoinInfoThumbprint)" }

if ($AzureADJoinCertificate -ne $null){
# Cert is now found, extract Device ID from Common Name
$AzureADDeviceID = ($AzureADJoinCertificate | Select-Object -ExpandProperty "Subject") -replace "CN=", ""
# Convert upper to lowercase.
$AzureADDeviceID = "$($AzureADDeviceID)".ToLower()
# Handle return value
return $AzureADDeviceID

} else {
# Last ditch effort, try and use the ThumbPrint (reg key) itself.
$AzureADDeviceID=$AzureADJoinInfoThumbprint
# Convert upper to lowercase.
$AzureADDeviceID = "$($AzureADDeviceID)".ToLower()
return $AzureADDeviceID

}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,35 @@ function Get-AzureADRegistrationCertificateThumbprint {

Version history:
1.0.0 - (2021-06-03) Function created
1.0.1 - (2023-05-10) @AzureToTheMax Updated for Cloud PCs which don't have their thumbprint as their JoinInfo key name.
#>
Process {
# Define Cloud Domain Join information registry path
$AzureADJoinInfoRegistryKeyPath = "HKLM:\SYSTEM\CurrentControlSet\Control\CloudDomainJoin\JoinInfo"

# Retrieve the child key name that is the thumbprint of the machine certificate containing the device identifier guid
$AzureADJoinInfoThumbprint = Get-ChildItem -Path $AzureADJoinInfoRegistryKeyPath | Select-Object -ExpandProperty "PSChildName"
# Check for a cert matching that thumbprint
$AzureADJoinCertificate = Get-ChildItem -Path "Cert:\LocalMachine\My" -Recurse | Where-Object { $PSItem.Thumbprint -eq $AzureADJoinInfoThumbprint }

if($AzureADJoinCertificate -ne $null){
# if a matching cert was found tied to that reg key (thumbprint) value, then that is the thumbprint and it can be returned.
$AzureADThumbprint = $AzureADJoinInfoThumbprint

# Handle return value
return $AzureADThumbprint

} else {

# If a cert was not found, that reg key was not the thumbprint but can be used to locate the cert as it is likely the Azure ID which is in the certs common name.
$AzureADJoinCertificate = Get-ChildItem -Path "Cert:\LocalMachine\My" -Recurse | Where-Object { $PSItem.Subject -like "CN=$($AzureADJoinInfoThumbprint)" }

#Pull thumbprint from cert
$AzureADThumbprint = $AzureADJoinCertificate.Thumbprint

# Handle return value
return $AzureADThumbprint
}

# Handle return value
return $AzureADJoinInfoThumbprint
}
}
}
16 changes: 11 additions & 5 deletions AADDeviceTrust.Client/Private/Get-PublicKeyBytesEncodedString.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ function Get-PublicKeyBytesEncodedString {
Author: Nickolaj Andersen / Thomas Kurth
Contact: @NickolajA
Created: 2021-06-07
Updated: 2021-06-07
Updated: 2023-05-10

Version history:
1.0.0 - (2021-06-07) Function created
1.0.1 - (2023-05-10) @AzureToTheMax - Updated to use X509 for the full public key with extended properties in the PEM format

Credits to Thomas Kurth for sharing his original C# code.
#>
Expand All @@ -27,14 +28,19 @@ function Get-PublicKeyBytesEncodedString {
[string]$Thumbprint
)
Process {

# Determine the certificate based on thumbprint input
$Certificate = Get-ChildItem -Path "Cert:\LocalMachine\My" -Recurse | Where-Object { $PSItem.Thumbprint -eq $Thumbprint }
if ($Certificate -ne $null) {
# Get the public key bytes
[byte[]]$PublicKeyBytes = $Certificate.GetPublicKey()
# Bring the cert into a X509 object
$X509 = [System.Security.Cryptography.X509Certificates.X509Certificate2]::New($Certificate)
#Set the type of export to perform
$type = [System.Security.Cryptography.X509Certificates.X509ContentType]::Cert
#Export the public cert
$PublicKeyBytes = $X509.Export($type, "")

# Handle return value
# Handle return value - convert to Base64
return [System.Convert]::ToBase64String($PublicKeyBytes)
}
}
}
}
16 changes: 9 additions & 7 deletions AADDeviceTrust.Client/Public/New-AADDeviceTrustBody.ps1
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
function New-AADDeviceTrustBody {
<#
.SYNOPSIS
Construct the body with the elements for a sucessful device trust validation required by a Function App that's leveraging the AADDeviceTrust.FunctionApp module.
Construct the body with the elements for a successful device trust validation required by a Function App that's leveraging the AADDeviceTrust.FunctionApp module.

.DESCRIPTION
Construct the body with the elements for a sucessful device trust validation required by a Function App that's leveraging the AADDeviceTrust.FunctionApp module.
Construct the body with the elements for a successful device trust validation required by a Function App that's leveraging the AADDeviceTrust.FunctionApp module.

.EXAMPLE
.\New-AADDeviceTrustBody.ps1
Expand All @@ -13,30 +13,32 @@ function New-AADDeviceTrustBody {
Author: Nickolaj Andersen
Contact: @NickolajA
Created: 2022-03-14
Updated: 2022-03-14
Updated: 2023-05-14

Version history:
1.0.0 - (2022-03-14) Script created
1.0.1 - (2023-05-10) @AzureToTheMax - Updated to no longer use Thumbprint field, no redundant.
1.0.2 - (2023-05-14) @AzureToTheMax - Updating to pull the Azure AD Device ID from the certificate itself.
#>
[CmdletBinding(SupportsShouldProcess = $true)]
param()
Process {
# Retrieve required data for building the request body
$AzureADDeviceID = Get-AzureADDeviceID
$AzureADDeviceID = Get-AzureADDeviceID # Still needed to form the signature.
$CertificateThumbprint = Get-AzureADRegistrationCertificateThumbprint
$Signature = New-RSACertificateSignature -Content $AzureADDeviceID -Thumbprint $CertificateThumbprint
$PublicKeyBytesEncoded = Get-PublicKeyBytesEncodedString -Thumbprint $CertificateThumbprint

# Construct client-side request header
$BodyTable = [ordered]@{
DeviceName = $env:COMPUTERNAME
DeviceID = $AzureADDeviceID
#DeviceID = $AzureADDeviceID - Will be pulled from the key.
Signature = $Signature
Thumbprint = $CertificateThumbprint
#Thumbprint = $CertificateThumbprint - Will be pulled from the key.
PublicKey = $PublicKeyBytesEncoded
}

# Handle return value
return $BodyTable
}
}
}
5 changes: 3 additions & 2 deletions AADDeviceTrust.FunctionApp/AADDeviceTrust.FunctionApp.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@
"Get-AzureADDeviceRecord",
"New-HashString",
"Test-AzureADDeviceAlternativeSecurityIds",
"Test-Encryption"
"Test-Encryption",
"Get-AzureADDeviceIDFromCertificate"
)

# Variables to export from this module
Expand Down Expand Up @@ -75,4 +76,4 @@

}



Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
function Get-AzureADDeviceIDFromCertificate {
<#
.SYNOPSIS
Used to pull the Azure Device ID from the provided Base64 certificate.

.DESCRIPTION
Used by the function app to pull the Azure Device ID from the provided Base64 certificate.

.NOTES
Author: Maxton Allen
Contact: @AzureToTheMax
Created: 2023-05-14
Updated: 2023-05-14

Version history:
1.0.0 - (2023-05-14) created
#>
param(
[parameter(Mandatory = $true, HelpMessage = "Specify a Base64 encoded value for which an Azure Device ID will be extracted.")]
[ValidateNotNullOrEmpty()]
[string]$Value
)
Process {
# Convert Value (cert) passed back to X502 Object
$X502 = [System.Security.Cryptography.X509Certificates.X509Certificate2]::New([System.Convert]::FromBase64String($Value))

# Get the Subject (issued to)
$Subject = $X502.Subject

# Remove the leading "CN="
$SubjectTrimed = $Subject.TrimStart("CN=")

# Handle return
Return $SubjectTrimed
}
}
5 changes: 4 additions & 1 deletion AADDeviceTrust.FunctionApp/Public/New-HashString.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ function New-HashString {

Version history:
1.0.0 - (2021-08-23) Function created

#AzureToTheMax was here - this function does not appear to be used anywhere? If it is, it may need to be updated to accept a full PEM and use the X502 class like the others.

#>
param(
[parameter(Mandatory = $true, HelpMessage = "Specify a Base64 encoded value for which a hash will be computed.")]
Expand All @@ -39,4 +42,4 @@ function New-HashString {
# Handle return value
return $ComputedHashString
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,14 @@ function Test-AzureADDeviceAlternativeSecurityIds {
Author: Nickolaj Andersen
Contact: @NickolajA
Created: 2021-06-07
Updated: 2021-06-07
Updated: 2023-05-10

Version history:
1.0.0 - (2021-06-07) Function created
1.0.1 - (2023-05-10) @AzureToTheMax
1. Updated Thumbprint compare to use actual PEM cert via X502 class rather than simply a passed and separate thumbprint value.
2. Updated Hash compare to use full PEM cert via the X502 class, pull out just the public key data, and compare from that like before.

#>
param(
[parameter(Mandatory = $true, HelpMessage = "Specify the alternativeSecurityIds.Key property from an Azure AD device record.")]
Expand All @@ -44,17 +48,30 @@ function Test-AzureADDeviceAlternativeSecurityIds {

switch ($Type) {
"Thumbprint" {
Write-Output "Using new X502 Thumbprint compare"

# Convert Value (cert) passed back to X502 Object
$X502 = [System.Security.Cryptography.X509Certificates.X509Certificate2]::New([System.Convert]::FromBase64String($Value))

# Validate match
if ($Value -match $AzureADDeviceAlternativeSecurityIds.Thumbprint) {
if ($X502.thumbprint -match $AzureADDeviceAlternativeSecurityIds.Thumbprint) {
return $true
}
else {
return $false
}
}
"Hash" {
Write-Output "Using new X502 hash compare"

# Convert Value (cert) passed back to X502 Object
$X502 = [System.Security.Cryptography.X509Certificates.X509Certificate2]::New([System.Convert]::FromBase64String($Value))

# Pull out just the public key, removing extended values
$X502Pub = [System.Convert]::ToBase64String($X502.PublicKey.EncodedKeyValue.rawData)

# Convert from Base64 string to byte array
$DecodedBytes = [System.Convert]::FromBase64String($Value)
$DecodedBytes = [System.Convert]::FromBase64String($X502Pub)

# Construct a new SHA256Managed object to be used when computing the hash
$SHA256Managed = New-Object -TypeName "System.Security.Cryptography.SHA256Managed"
Expand All @@ -75,4 +92,4 @@ function Test-AzureADDeviceAlternativeSecurityIds {
}
}
}
}
}
17 changes: 13 additions & 4 deletions AADDeviceTrust.FunctionApp/Public/Test-Encryption.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ function Test-Encryption {
Author: Nickolaj Andersen / Thomas Kurth
Contact: @NickolajA
Created: 2021-06-07
Updated: 2021-06-07
Updated: 2023-05-10

Version history:
1.0.0 - (2021-06-07) Function created
1.0.1 - (2023-05-10) @AzureToTheMax - Updated to use full PEM cert via X502, extract the public key, and perform test like before using that.

Credits to Thomas Kurth for sharing his original C# code.
#>
Expand All @@ -40,8 +41,16 @@ function Test-Encryption {
[string]$Content
)
Process {
# Convert from Base64 string to byte array
$PublicKeyBytes = [System.Convert]::FromBase64String($PublicKeyEncoded)

Write-Output "Using new X502 encryption test"
# Convert Value (cert) passed back to X502 Object
$X502 = [System.Security.Cryptography.X509Certificates.X509Certificate2]::New([System.Convert]::FromBase64String($PublicKeyEncoded))

# Pull out just the public key, removing extended values
$X502Pub = [System.Convert]::ToBase64String($X502.PublicKey.EncodedKeyValue.rawData)

# Convert encoded public key from Base64 string to byte array
$PublicKeyBytes = [System.Convert]::FromBase64String($X502Pub)

# Convert signature from Base64 string
[byte[]]$Signature = [System.Convert]::FromBase64String($Signature)
Expand Down Expand Up @@ -74,4 +83,4 @@ function Test-Encryption {
# Verify the signature with the computed hash of the content using the public key
$PublicKey.VerifyHash($ComputedHash, $Signature, [System.Security.Cryptography.HashAlgorithmName]::SHA256, [System.Security.Cryptography.RSASignaturePadding]::Pkcs1)
}
}
}
Loading