<# .SYNOPSIS A script to check the SSL certificates currently used as SSL trust anchors. .NOTES Author: Vincent Santa Maria [vsantamaria@vmware.com] Version: 2.2 .DESCRIPTION This script will parse the output of "%VMWARE_CIS_HOME%\VMware Identity Services\lstool\scripts\lstool.py" and provide information on each unique certificate being used as an SSL trust anchor for a solution registered with the Lookup Service. .PARAMETER ServiceIDs Prints the Lookup Service service IDs using each SSL certificate for one or more endpoints. .PARAMETER Endpoints Prints the URIs using each unique SSL certificate. .PARAMETER ViewMachineSSL Shows information on the current Machine SSL certificate for each node in the SSO domain so you can compare against the unique certificates being used as SSL trust anchors. .PARAMETER Fix This will attempt to fix the SSL trust anchors by using the "%VMWARE_CIS_HOME%\VMware Identity Services\lstool\scripts\ls_update_certs.py" tool. The specified thumbprint will be from the Endpoint Certificate you wish to replace. .PARAMETER Debug Prints the certificate hash for manual verification. This happens when there is stderr intermixed with the normal output from the lstool.py script. .PARAMETER SHA256 Prints the SHA256 fingerprint instead of the SHA1 fingerprint, since some solutions display the SHA256 fingerprint of the vCenter/PSC during certificate verification. .PARAMETER Text Prints the full human-readable information about the certificate. .EXAMPLE .\check-trust-anchors.ps1 -ServiceIDs .EXAMPLE .\check-trust-anchors.ps1 -Endpoints .EXAMPLE .\check-trust-anchors.ps1 -ViewMachineSSL .EXAMPLE .\check-trust-anchors.ps1 -Fix .EXAMPLE .\check-trust-anchors.ps1 -Debug #> param ( [switch]$ServiceIDs, [switch]$Endpoints, [switch]$ViewMachineSSL, [switch]$Fix, [switch]$Debug, [switch]$SHA256, [switch]$Text ) function Get-CertInfo { Param($Cert, $Algorithm, $FullText) if ($FullText) { $cert_info = $Cert | &"$Env:VMWARE_OPENSSL_BIN" x509 -text -noout -fingerprint -$Algorithm 2>$null Write-Host ($cert_info | Out-String) return } $algorithm_UC = $Algorithm.ToUpper() $cert_info = $Cert | &"$Env:VMWARE_OPENSSL_BIN" x509 -text -noout -fingerprint -$Algorithm 2>$null | Select-String -Pattern 'Issuer:|Subject:|Validity|Not Before:|Not After :|Fingerprint' $cert_info = $cert_info -replace "^\s+","`t" $Cert | &"$Env:VMWARE_OPENSSL_BIN" x509 -noout -checkend 0 > $null 2>&1 if ($?) { $expired=1 } else { $expired=0 } $cert_issuer = $cert_info | Select-String -Pattern 'Issuer:' $cert_start = $cert_info | Select-String -Pattern 'Not Before' $cert_end = $cert_info | Select-String -Pattern 'Not After' $cert_subject = $cert_info | Select-String -Pattern 'Subject:' $cert_subject = $cert_subject -replace 'Subject:','' -replace '^\s+','' $cert_fingerprint = $cert_info | Select-String -Pattern "$algorithm_UC Fingerprint" $cert_fingerprint = $cert_fingerprint -replace "$algorithm_UC Fingerprint=",'' Write-Host $cert_issuer Write-Host "`tValidity" if ($expired) { Write-Host "`t$cert_start" -ForegroundColor Red Write-Host "`t$cert_end" -ForegroundColor Red } else { Write-Host "`t$cert_start" Write-Host "`t$cert_end" } Write-Host "`tSubject: " -ForegroundColor Green -NoNewline Write-Host $cert_subject Write-Host "`t$algorithm_UC Fingerprint=" -NoNewline Write-Host $cert_fingerprint -ForegroundColor Yellow } $lstool_output = &"$Env:VMWARE_PYTHON_BIN" "$Env:VMWARE_CIS_HOME\VMware Identity Services\lstool\scripts\lstool.py" list --url http://localhost:7080/lookupservice/sdk 2>$null | Select-String -Pattern 'Service ID:|URL:|SSL trust:|^[0-9A-Za-z/\+]' -CaseSensitive | Out-String $lstool_output = $lstool_output -replace "`r",'' -replace "`n",'' -replace '\s','' -replace 'SSLtrust:',"|SSLtrust:" -replace 'URL:',"|URL:" -replace 'ServiceID:',"|ServiceID:" $lstool_output | Add-Content c:\windows\temp\lstool_output.txt $trust_anchors = $lstool_output.split('|') | Select-String -Pattern '^SSLtrust' | Sort-Object -Unique if ($SHA256) { $sha_algorithm = 'sha256' } else { $sha_algorithm = 'sha1' } if ($Text) { $full_cert_text = 1 } else { $full_cert_text = 0 } $anchor_count = 1 ForEach ($anchor in $trust_anchors) { $line = $anchor -split ':' $hash = $line[1] $cert_raw = $hash -replace ".{64}","$&`n" $temp_cert = "-----BEGIN CERTIFICATE-----`n" $temp_cert += $cert_raw $temp_cert += "`n-----END CERTIFICATE-----" Write-Host "-----Endpoint Certificate ${anchor_count}-----" -ForegroundColor Cyan Write-Host "Certificate Info:" Get-CertInfo -Cert $temp_cert -Algorithm $sha_algorithm -FullText $full_cert_text if ($Debug) { Write-Host "`tCert Hash: $hash" } if ($ServiceIDs) { $service_ids = New-Object System.Collections.Generic.List[System.Object] $data = $lstool_output.split('|') | Select-String -Pattern '^SSLtrust|^ServiceID' [array]::Reverse($data) $hash_matches=0 ForEach ($line in $data) { $parts = $line -split ':' if ($line -match '^ServiceID') { if($hash_matches) { $current_service_id = $line -replace 'ServiceID:','' if (! ($service_ids -contains $current_service_id)) { $service_ids.Add($current_service_id) } $hash_matches=0 } } else { $current_hash = $parts[1] if ($current_hash -eq $hash) { $hash_matches=1 } else { $hash_matches=0 } } } $num_service_ids = $service_ids.count Write-Host "Service IDs ($num_service_ids)" ForEach ($service_id in $service_ids | Sort-Object) { Write-Host "`t$service_id" } } if ($Endpoints) { $endpoint_list = New-Object System.Collections.Generic.List[System.Object] $data = $lstool_output.split('|') | Select-String -Pattern '^SSLtrust:|^URL:' [array]::Reverse($data) $hash_matches=0 ForEach ($line in $data) { $parts = $line -split ':' if ($line -match '^URL') { if ($hash_matches) { $current_url = $line -replace 'URL:','' if (! ($endpoint_list -contains $current_url)) { $endpoint_list.Add($current_url) } $hash_matches=0 } } else { $current_hash = $parts[1] if ($current_hash -eq $hash) { $hash_matches=1 } else { $hash_matches=0 } } } $num_endpoints = $endpoint_list.count Write-Host "Endpoints ($num_endpoints)" ForEach ($endpoint in $endpoint_list | Sort-Object) { Write-Host "`t$endpoint" } } Write-Host "--------------------------------" -ForegroundColor Cyan $anchor_count++ } if ($ViewMachineSSL) { $machine_dn = (Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\VMwareDirectoryService -Name "dcAccountDN").dcAccountDN $machine_pw = (Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\VMwareDirectoryService -Name "dcAccountPassword").dcAccountPassword $SSO_site = &"$Env:VMWARE_CIS_HOME\vmafdd\vmafd-cli.exe" get-site-name --server-name localhost $SSO_domain = &"$Env:VMWARE_CIS_HOME\vmafdd\vmafd-cli.exe" get-domain-name --server-name localhost $SSO_DC_branch = $SSO_domain -replace '\.',',dc=' $SSO_DC_branch = "dc=${SSO_DC_branch}" $LDAP_host = "localhost" $LDAP_port = "389" $LDAP_dn = "LDAP://${LDAP_host}:${LDAP_port}" $LDAP_search_DN = "cn=ServiceRegistrations,cn=LookupService,cn=$SSO_site,cn=Sites,cn=Configuration,$SSO_DC_branch" $LDAP_auth = [System.DirectoryServices.AuthenticationTypes]::FastBind $LDAP_de = New-Object System.DirectoryServices.DirectoryEntry("${LDAP_dn}/${LDAP_search_DN}", $machine_dn, $machine_pw, $LDAP_auth) $LDAP_ds = New-Object System.DirectoryServices.DirectorySearcher($LDAP_de, "(objectclass=vmwLKUPEndpointRegistration)") $LDAP_ds.PageSize=1500 $LDAP_ds.SizeLimit=1500 $LDAP_ds.PropertiesToLoad.Add('vmwLKUPURI') $nodes = New-Object System.Collections.Generic.List[System.Object] $results = $LDAP_ds.FindAll() foreach ($object in $results) { $endpoint = $object.properties $uri = $endpoint.vmwlkupuri if ($uri -notlike '*localhost*') { $fields = $uri -split '/' $location = $fields[2] -split ':' $fqdn = $location[0] if ($nodes -notcontains $fqdn) { $nodes.Add($fqdn) } } } ForEach ($node in $nodes) { Write-Host "-----Machine SSL Certificate-----" -ForegroundColor Cyan Write-Host $node -ForegroundColor Cyan Write-Host "Certificate Info:" $machine_ssl_cert = "Q" | &"$Env:VMWARE_OPENSSL_BIN" s_client -host $node -port 443 2>$null if ($machine_ssl_cert -eq $null) { Write-Host "`tUnable to retrieve certificate information from $node" -ForegroundColor Yellow } else { Get-CertInfo -Cert $machine_ssl_cert -Algorithm $sha_algorithm -FullText $full_cert_text } Write-Host "---------------------------------" -ForegroundColor Cyan } } if($Fix) { Write-Host "`nSSL Trust Anchor Repair" -ForegroundColor Cyan Write-Host "--------------------------------" -ForegroundColor Cyan Write-Host "This process will attempt to update the SSL trust anchors for Lookup Service registrations using native Lookup Service libararies. These changes should propagate to all PSCs in the SSO domain." Write-Host "`nIt is strongly recommended that you take offline snapshots of all PSCs in the SSO domain before proceeding!" -ForegroundColor Yellow $confirm = Read-Host -Prompt "`nProceed with updating trust anchors? [Y/N]: " if($confirm -match '^[yY]') { $sso_domain = &"$Env:VMWARE_CIS_HOME\vmafdd\vmafd-cli.exe" get-domain-name --server-name localhost $credentials = Get-Credential -Message "Enter a Single Sign-On Administrator account: " -UserName administrator@$sso_domain if($credentials) { $username = $credentials.Username $password = [System.Net.NetworkCredential]::new("", $credentials.Password).Password $fingerprint = Read-Host -Prompt "`nEnter the fingerprint of the trust anchor(s) to update: " $node = Read-Host -Prompt "Enter the FQDN of the node to update: " Write-Host "`nObtaining Machine SSL certificate for " -NoNewline Write-Host $node -ForegroundColor Green -NoNewline Write-Host ". Since this is Windows, it can take up to 30 seconds, please wait...`n" &"$Env:VMWARE_OPENSSL_BIN" s_client -host $node -port 443 2>$null | &"$Env:VMWARE_OPENSSL_BIN" x509 2>$null | Set-Content c:\windows\temp\update-trust-anchor.crt &"$Env:VMWARE_OPENSSL_BIN" x509 -in c:\windows\temp\update-trust-anchor.crt 2>$null > $null if(!$LastExitCode) { &"$Env:VMWARE_PYTHON_BIN" "$Env:VMWARE_CIS_HOME\VMware Identity Services\lstool\scripts\ls_update_certs.py" --url http://localhost:7080/lookupservice/sdk --fingerprint $fingerprint --certfile c:\windows\temp\update-trust-anchor.crt --user $username --password $password 2>c:\windows\temp\ls_update_certs.stderr if(!$LastExitCode) { Write-Host "`nPlease restart services on all PSC/vCenter nodes in this SSO domain." -ForegroundColor Yellow } else { Write-Host "Error updating trust anchors." -ForegroundColor Yellow } } else { Write-Host "Unable to get SSL certificate from $node" -ForegroundColor Yellow } } } else { Write-Host "Operation aborted. Exiting..." -ForegroundColor Yellow } }