Jump to content

Accessing UEM API via certificate


Recommended Posts

  • 4 weeks later...
  • Employee

Here is an example on how to do this in PowerShell. The example uses the search API to find the device with ID 154335 but is really just to illustrate an API being used. The certificate was exported to the personal cert store and has the subject as shown below, which would need to be updated with the approprate subject of the certificate to use. The API server name and API Tenant code would also need to be specified.

Add-Type -AssemblyName System.Security

function Get-CMSURLAuthorizationHeader
{
    [CmdletBinding()]
    [OutputType([string])]
    Param
    (
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [uri]$URL,

        [Parameter(Mandatory=$true,
                    ValueFromPipeline)]
        [System.Security.Cryptography.X509Certificates.X509Certificate2]
        $Certificate
    )

    Process
    {
       TRY
       {
            $bytes = [System.Text.Encoding]::UTF8.GetBytes(($Url.AbsolutePath))
            $MemStream = New-Object -TypeName System.Security.Cryptography.Pkcs.ContentInfo -ArgumentList (,$bytes) -ErrorAction Stop
            $SignedCMS = New-Object -TypeName System.Security.Cryptography.Pkcs.SignedCms -ArgumentList $MemStream,$true -ErrorAction Stop
            $CMSigner = New-Object -TypeName System.Security.Cryptography.Pkcs.CmsSigner -ArgumentList $Certificate -Property @{IncludeOption = [System.Security.Cryptography.X509Certificates.X509IncludeOption]::EndCertOnly} -ErrorAction Stop
            $null = $CMSigner.SignedAttributes.Add((New-Object -TypeName System.Security.Cryptography.Pkcs.Pkcs9SigningTime))
            $SignedCMS.ComputeSignature($CMSigner)
            $CMSHeader = '{0}{1}{2}' -f 'CMSURL','`1 ',$([System.Convert]::ToBase64String(($SignedCMS.Encode())))
            Write-Output -InputObject $CMSHeader
        }
        Catch
        {
            Write-Error -Exception $_.exception -ErrorAction stop
        }
    }
}

$Certificate = Get-ChildItem -Path Cert:\CurrentUser\my | Where-Object Subject -eq 'CN=8091:APICBA'

$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "$(Get-CMSURLAuthorizationHeader -URL $Url -Certificate $Certificate)")
$headers.Add("aw-tenant-code", "****** REST API TENANT CODE GOES HERE ******")
$headers.Add("Content-Type", "application/json")

$URI = 'https://{api server}.awmdm.com/api/mdm/devices?searchBy=DeviceId&id=154335'

try
{
   $response = Invoke-WebRequest -Method Get -Uri $URI -Headers $Headers -ErrorAction Stop
   $response.content | ConvertFrom-Json
}
catch
{
   Write-Output $_.Exception.Message
}

 

  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...
On 7/25/2024 at 11:56 PM, Glyn Dobson said:

Here is an example on how to do this in PowerShell. The example uses the search API to find the device with ID 154335 but is really just to illustrate an API being used. The certificate was exported to the personal cert store and has the subject as shown below, which would need to be updated with the approprate subject of the certificate to use. The API server name and API Tenant code would also need to be specified.

Add-Type -AssemblyName System.Security

function Get-CMSURLAuthorizationHeader
{
    [CmdletBinding()]
    [OutputType([string])]
    Param
    (
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [uri]$URL,

        [Parameter(Mandatory=$true,
                    ValueFromPipeline)]
        [System.Security.Cryptography.X509Certificates.X509Certificate2]
        $Certificate
    )

    Process
    {
       TRY
       {
            $bytes = [System.Text.Encoding]::UTF8.GetBytes(($Url.AbsolutePath))
            $MemStream = New-Object -TypeName System.Security.Cryptography.Pkcs.ContentInfo -ArgumentList (,$bytes) -ErrorAction Stop
            $SignedCMS = New-Object -TypeName System.Security.Cryptography.Pkcs.SignedCms -ArgumentList $MemStream,$true -ErrorAction Stop
            $CMSigner = New-Object -TypeName System.Security.Cryptography.Pkcs.CmsSigner -ArgumentList $Certificate -Property @{IncludeOption = [System.Security.Cryptography.X509Certificates.X509IncludeOption]::EndCertOnly} -ErrorAction Stop
            $null = $CMSigner.SignedAttributes.Add((New-Object -TypeName System.Security.Cryptography.Pkcs.Pkcs9SigningTime))
            $SignedCMS.ComputeSignature($CMSigner)
            $CMSHeader = '{0}{1}{2}' -f 'CMSURL','`1 ',$([System.Convert]::ToBase64String(($SignedCMS.Encode())))
            Write-Output -InputObject $CMSHeader
        }
        Catch
        {
            Write-Error -Exception $_.exception -ErrorAction stop
        }
    }
}

$Certificate = Get-ChildItem -Path Cert:\CurrentUser\my | Where-Object Subject -eq 'CN=8091:APICBA'

$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "$(Get-CMSURLAuthorizationHeader -URL $Url -Certificate $Certificate)")
$headers.Add("aw-tenant-code", "****** REST API TENANT CODE GOES HERE ******")
$headers.Add("Content-Type", "application/json")

$URI = 'https://{api server}.awmdm.com/api/mdm/devices?searchBy=DeviceId&id=154335'

try
{
   $response = Invoke-WebRequest -Method Get -Uri $URI -Headers $Headers -ErrorAction Stop
   $response.content | ConvertFrom-Json
}
catch
{
   Write-Output $_.Exception.Message
}

 

Using this code, I get "Get-CMSURLAuthorizationHeader : Exception calling "ComputeSignature" with "1" argument(s): "Keyset does not exist". Please advise

Link to comment
Share on other sites

  • Employee
40 minutes ago, Otto said:

Using this code, I get "Get-CMSURLAuthorizationHeader : Exception calling "ComputeSignature" with "1" argument(s): "Keyset does not exist". Please advise

Try running this and see if it gives anything extra. Update the URL with the full URL and also change the CN for the cert, left mine in as an example.

[uri]$Url = 'https://as1784.awmdm.com/api/mdm/devices?searchBy=DeviceId&id=154335'
$Certificate = Get-ChildItem -Path Cert:\CurrentUser\my | Where-Object Subject -eq 'CN=8091:APICBA'

$bytes = [System.Text.Encoding]::UTF8.GetBytes(($Url.AbsolutePath))
$MemStream = New-Object -TypeName System.Security.Cryptography.Pkcs.ContentInfo -ArgumentList (,$bytes) -ErrorAction Stop
$SignedCMS = New-Object -TypeName System.Security.Cryptography.Pkcs.SignedCms -ArgumentList $MemStream,$true -ErrorAction Stop
$CMSigner = New-Object -TypeName System.Security.Cryptography.Pkcs.CmsSigner -ArgumentList $Certificate -Property @{IncludeOption = [System.Security.Cryptography.X509Certificates.X509IncludeOption]::EndCertOnly} -ErrorAction Stop
$null = $CMSigner.SignedAttributes.Add((New-Object -TypeName System.Security.Cryptography.Pkcs.Pkcs9SigningTime))
$SignedCMS.ComputeSignature($CMSigner)
$CMSHeader = '{0}{1}{2}' -f 'CMSURL','`1 ',$([System.Convert]::ToBase64String(($SignedCMS.Encode())))
Write-Output -InputObject $CMSHeader

 

Link to comment
Share on other sites

45 minutes ago, Glyn Dobson said:

Try running this and see if it gives anything extra. Update the URL with the full URL and also change the CN for the cert, left mine in as an example.

[uri]$Url = 'https://as1784.awmdm.com/api/mdm/devices?searchBy=DeviceId&id=154335'
$Certificate = Get-ChildItem -Path Cert:\CurrentUser\my | Where-Object Subject -eq 'CN=8091:APICBA'

$bytes = [System.Text.Encoding]::UTF8.GetBytes(($Url.AbsolutePath))
$MemStream = New-Object -TypeName System.Security.Cryptography.Pkcs.ContentInfo -ArgumentList (,$bytes) -ErrorAction Stop
$SignedCMS = New-Object -TypeName System.Security.Cryptography.Pkcs.SignedCms -ArgumentList $MemStream,$true -ErrorAction Stop
$CMSigner = New-Object -TypeName System.Security.Cryptography.Pkcs.CmsSigner -ArgumentList $Certificate -Property @{IncludeOption = [System.Security.Cryptography.X509Certificates.X509IncludeOption]::EndCertOnly} -ErrorAction Stop
$null = $CMSigner.SignedAttributes.Add((New-Object -TypeName System.Security.Cryptography.Pkcs.Pkcs9SigningTime))
$SignedCMS.ComputeSignature($CMSigner)
$CMSHeader = '{0}{1}{2}' -f 'CMSURL','`1 ',$([System.Convert]::ToBase64String(($SignedCMS.Encode())))
Write-Output -InputObject $CMSHeader

 

Hi Glyn, thanks for the quick response.

I am wondering if I have to add some extra Add-Type

Here is my code and the response:

$tenantAPIKey = 'dz52iegnlWe9Mgd1r4xnbYMW9gmzzkWVduUP5abNvqg='
$Certificate = Get-ChildItem -Path Cert:\LocalMachine\my | Where-Object Subject -eq 'CN=12063:RESTAPI4EUD'
[uri]$Url = 'https://mdm.airfrance.fr/api/mdm/dep/profiles/search?PageSize=40000'
Add-Type -AssemblyName System.Security

$bytes = [System.Text.Encoding]::UTF8.GetBytes(($Url.AbsolutePath))
$MemStream = New-Object -TypeName System.Security.Cryptography.Pkcs.ContentInfo -ArgumentList (,$bytes) -ErrorAction Stop
$SignedCMS = New-Object -TypeName System.Security.Cryptography.Pkcs.SignedCms -ArgumentList $MemStream,$true -ErrorAction Stop
$CMSigner = New-Object -TypeName System.Security.Cryptography.Pkcs.CmsSigner -ArgumentList $Certificate -Property @{IncludeOption = [System.Security.Cryptography.X509Certificates.X509IncludeOption]::EndCertOnly} -ErrorAction Stop
$null = $CMSigner.SignedAttributes.Add((New-Object -TypeName System.Security.Cryptography.Pkcs.Pkcs9SigningTime))
$SignedCMS.ComputeSignature($CMSigner)
$CMSHeader = '{0}{1}{2}' -f 'CMSURL','`1 ',$([System.Convert]::ToBase64String(($SignedCMS.Encode())))
Write-Output -InputObject $CMSHeader

 

Response 1:

CMSURL`1 

 

Response 2:

Exception calling "ComputeSignature" with "1" argument(s): "Keyset does not exist
"
At C:\MDM\Omnissa.ps1:11 char:1
+ $SignedCMS.ComputeSignature($CMSigner)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : CryptographicException
 
Exception calling "Encode" with "0" argument(s): "The CMS message is not signed."
At C:\MDM\Omnissa.ps1:12 char:46
+ ... URL','`1 ',$([System.Convert]::ToBase64String(($SignedCMS.Encode())))
+                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : InvalidOperationException
 
Thanks in advance

Link to comment
Share on other sites

  • Employee

Not sure what going on there.  The Add-Type was missing so added it to the code block below. When I run this, $CMSHeader is set correctly. This is pointing to my certificate, if it can't find the certificate it throws an "The recipient certificate is not specified" which would be expected. I couldn't paste and run your code in due to formatting issues but it looks the same as what I have. Only thing I can think is that there is some kind of certificate issue.

Looks like the line its failing on is: 

$SignedCMS.ComputeSignature($CMSigner)

After running my code below, $SignedCMS = 

image.png.4984c6dbc6cded087dad0a37a5fc844e.png

and $CMSigner = 

image.png.5cb3349604af6f6591cfa34b98d96a26.png

Might be worth checking to see what these two values are set to prior to running ComputeSignature.

Side note, I would also recommend editing your post above and removing your tenantAPIKey since you would want to keep this internal only.

Add-Type -AssemblyName System.Security

[uri]$Url = 'https://mdm.airfrance.fr/api/mdm/dep/profiles/search?PageSize=40000'
$Certificate = Get-ChildItem -Path Cert:\CurrentUser\my | Where-Object Subject -eq 'CN=8091:APICBA'

$bytes = [System.Text.Encoding]::UTF8.GetBytes(($Url.AbsolutePath))
$MemStream = New-Object -TypeName System.Security.Cryptography.Pkcs.ContentInfo -ArgumentList (,$bytes) -ErrorAction Stop
$SignedCMS = New-Object -TypeName System.Security.Cryptography.Pkcs.SignedCms -ArgumentList $MemStream,$true -ErrorAction Stop
$CMSigner = New-Object -TypeName System.Security.Cryptography.Pkcs.CmsSigner -ArgumentList $Certificate -Property @{IncludeOption = [System.Security.Cryptography.X509Certificates.X509IncludeOption]::EndCertOnly} -ErrorAction Stop
$null = $CMSigner.SignedAttributes.Add((New-Object -TypeName System.Security.Cryptography.Pkcs.Pkcs9SigningTime))
$SignedCMS.ComputeSignature($CMSigner)
$CMSHeader = '{0}{1}{2}' -f 'CMSURL','`1 ',$([System.Convert]::ToBase64String(($SignedCMS.Encode())))
Write-Output -InputObject $CMSHeader

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...