diff --git a/CHANGELOG.md b/CHANGELOG.md index 0162aff..ed6b284 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,20 @@ +2.6.2 +* Fixed error when attempting to connect to remote computer using UO service account +* Fixed error when connecting to remote computer using HTTPS; was defaulting to HTTP +* Fixed the creation of a certificate when the Cryptographic Service Provider was changed by the user +* Updated logic when getting the CSP. Now supports modern CHG and legacy CAPI APIs. This will allow the CSP to show in the stores inventory. +* Re-factored code to eliminate warnings +* Bumped up he following packages to eliminate .net vulnerabilities and obsolete packages: + * Keyfactor.Orchestrators.IOrchestratorJobExtensions" Version="1.0.0" + * Microsoft.PowerShell.SDK" Version="7.4.10" Condition="'$(TargetFramework)' == 'net8.0'" + * runtime.linux-arm64.runtime.native.System.IO.Ports" Version="9.0.5" + * runtime.osx-arm64.runtime.native.System.IO.Ports" Version="9.0.5" + * System.Formats.Asn1" Version="8.0.2" Condition="'$(TargetFramework)' == 'net6.0'" + * System.Formats.Asn1" Version="9.0.0" Condition="'$(TargetFramework)' == 'net8.0'" + * System.IO.Packaging" Version="6.0.2" Condition="'$(TargetFramework)' == 'net6.0'" + * System.IO.Packaging" Version="8.0.1" Condition="'$(TargetFramework)' == 'net8.0'" + * System.Text.Json" Version="8.0.5" + 2.6.1 * Documentation updates for the 2.6 release * Fix a naming typo in the 2.5 migration SQL script @@ -11,6 +28,7 @@ * Added the ability to run the extension in a Linux environment. To utilize this change, for each Cert Store Types (WinCert/WinIIS/WinSQL), add ssh to the Custom Field WinRM Protocol. When using ssh as a protocol, make sure to enter the appropriate ssh port number under WinRM Port. * NOTE: For legacy purposes the Display names WinRM Protocol and WinRM Port are maintained although the type of protocols now includes ssh. * Moved all inventory and management jobs to external PowerShell script file .\PowerShellScripts\WinCertScripts.ps1 +* Changed how IIS Bound certificates are deleted; Certificates are only deleted from the certificate store when the certificate is NOT BOUND to any other sites. * NOTE: This version was not publicly released. 2.5.1 @@ -19,6 +37,7 @@ 2.5.0 * Added the Bindings to the end of the thumbprint to make the alias unique. * Using new IISWebBindings cmdlet to use additional SSL flags when binding certificate to website. +* NOTE: The property SNIFlag has changed from a multi-select to a string with default of "0". To properly use the new SNI/SSL flags you can delete the SNIFlag from the store type and re-add the field as described in the ReadMe. If you have several existing cert stores, you may can execute the SQL script (IISU Sni Flag 2.5 upgrade script) to update the field type. Consult your Keyfactor Rep for help. * Added multi-platform support for .Net6 and .Net8. * Updated various PowerShell scripts to handle both .Net6 and .Net8 differences (specifically the absence of the WebAdministration module in PS SDK 7.4.x+) * Fixed issue to update multiple websites when using the same cert. diff --git a/IISU/ClientPSCertStoreReEnrollment.cs b/IISU/ClientPSCertStoreReEnrollment.cs index 945d595..d769d9b 100644 --- a/IISU/ClientPSCertStoreReEnrollment.cs +++ b/IISU/ClientPSCertStoreReEnrollment.cs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Ignore Spelling: Keyfactor +// Ignore Spelling: Keyfactor Reenrollment // 021225 rcp Cleaned up and removed unnecessary code @@ -40,7 +40,9 @@ internal class ClientPSCertStoreReEnrollment private readonly IPAMSecretResolver _resolver; private PSHelper _psHelper; +#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. private Collection? _results; +#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. public ClientPSCertStoreReEnrollment(ILogger logger, IPAMSecretResolver resolver) { diff --git a/IISU/ImplementedStoreTypes/Win/Inventory.cs b/IISU/ImplementedStoreTypes/Win/Inventory.cs index 9f0dd2a..0884751 100644 --- a/IISU/ImplementedStoreTypes/Win/Inventory.cs +++ b/IISU/ImplementedStoreTypes/Win/Inventory.cs @@ -14,6 +14,8 @@ // 021225 rcp 2.6.0 Cleaned up and verified code +// Ignore Spelling: Keyfactor + using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -31,9 +33,11 @@ public class Inventory : WinCertJobTypeBase, IInventoryJobExtension { private ILogger _logger; public string ExtensionName => "WinCertInventory"; - + +#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. Collection? results = null; - +#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. + public Inventory() { diff --git a/IISU/ImplementedStoreTypes/Win/Management.cs b/IISU/ImplementedStoreTypes/Win/Management.cs index 0a0be75..bbb860f 100644 --- a/IISU/ImplementedStoreTypes/Win/Management.cs +++ b/IISU/ImplementedStoreTypes/Win/Management.cs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License.using Keyfactor.Logging; -// Ignore Spelling: Keyfactor +// Ignore Spelling: Keyfactor crypto // 021225 rcp 2.6.0 Cleaned up and verified code @@ -35,7 +35,9 @@ public class Management : WinCertJobTypeBase, IManagementJobExtension private ILogger _logger; private PSHelper _psHelper; +#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. private Collection? _results = null; +#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. // Function wide config values private string _clientMachineName = string.Empty; @@ -95,7 +97,9 @@ public JobResult ProcessJob(ManagementJobConfiguration config) { string certificateContents = config.JobCertificate.Contents; string privateKeyPassword = config.JobCertificate.PrivateKeyPassword; +#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. string? cryptoProvider = config.JobProperties["ProviderName"]?.ToString(); +#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. complete = AddCertificate(certificateContents, privateKeyPassword, cryptoProvider); _logger.LogTrace($"Completed adding the certificate to the store"); diff --git a/IISU/ImplementedStoreTypes/WinIIS/IISBindingInfo.cs b/IISU/ImplementedStoreTypes/WinIIS/IISBindingInfo.cs index 7212b8a..58b9a60 100644 --- a/IISU/ImplementedStoreTypes/WinIIS/IISBindingInfo.cs +++ b/IISU/ImplementedStoreTypes/WinIIS/IISBindingInfo.cs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Ignore Spelling: Keyfactor IISU +// Ignore Spelling: Keyfactor IISU Sni Aliase // 021225 rcp 2.6.0 Cleaned up and verified code @@ -29,7 +29,9 @@ public class IISBindingInfo public string Protocol { get; set; } public string IPAddress { get; set; } public string Port { get; set; } +#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. public string? HostName { get; set; } +#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. public string SniFlag { get; set; } public string Thumbprint { get; private set; } diff --git a/IISU/ImplementedStoreTypes/WinIIS/Inventory.cs b/IISU/ImplementedStoreTypes/WinIIS/Inventory.cs index 5995bae..af45bdd 100644 --- a/IISU/ImplementedStoreTypes/WinIIS/Inventory.cs +++ b/IISU/ImplementedStoreTypes/WinIIS/Inventory.cs @@ -14,6 +14,8 @@ // 021225 rcp 2.6.0 Cleaned up and verified code +// Ignore Spelling: Keyfactor IISU + using Keyfactor.Logging; using Keyfactor.Orchestrators.Common.Enums; using Keyfactor.Orchestrators.Extensions; @@ -30,7 +32,9 @@ namespace Keyfactor.Extensions.Orchestrator.WindowsCertStore.IISU public class Inventory : WinCertJobTypeBase, IInventoryJobExtension { private ILogger _logger; +#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. Collection? results = null; +#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. public string ExtensionName => "WinIISUInventory"; diff --git a/IISU/ImplementedStoreTypes/WinIIS/Management.cs b/IISU/ImplementedStoreTypes/WinIIS/Management.cs index 280bdb3..bbd19c1 100644 --- a/IISU/ImplementedStoreTypes/WinIIS/Management.cs +++ b/IISU/ImplementedStoreTypes/WinIIS/Management.cs @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Ignore Spelling: Keyfactor IISU Crypto using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -34,7 +35,9 @@ public class Management : WinCertJobTypeBase, IManagementJobExtension private ILogger _logger; private PSHelper _psHelper; +#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. private Collection? _results = null; +#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. // Function wide config values private string _clientMachineName = string.Empty; @@ -99,11 +102,15 @@ public JobResult ProcessJob(ManagementJobConfiguration config) { string certificateContents = config.JobCertificate.Contents; string privateKeyPassword = config.JobCertificate.PrivateKeyPassword; +#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. string? cryptoProvider = config.JobProperties["ProviderName"]?.ToString(); +#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. // Add Certificate to Cert Store try { + IISBindingInfo bindingInfo = new IISBindingInfo(config.JobProperties); + OrchestratorJobStatusJobResult psResult = OrchestratorJobStatusJobResult.Unknown; string failureMessage = ""; @@ -112,9 +119,8 @@ public JobResult ProcessJob(ManagementJobConfiguration config) _logger.LogTrace($"New thumbprint: {newThumbprint}"); // Bind Certificate to IIS Site - if (newThumbprint != null) + if (!string.IsNullOrEmpty(newThumbprint)) { - IISBindingInfo bindingInfo = new IISBindingInfo(config.JobProperties); _logger.LogTrace("Returned after binding certificate to store"); var results = WinIISBinding.BindCertificate(_psHelper, bindingInfo, newThumbprint, "", _storePath); if (results != null && results.Count > 0) @@ -172,6 +178,14 @@ public JobResult ProcessJob(ManagementJobConfiguration config) FailureMessage = failureMessage }; } + else + { + complete = new JobResult + { + Result = OrchestratorJobStatusJobResult.Failure, + JobHistoryId = _jobHistoryID, + FailureMessage = $"No thumbprint was returned. Unable to bind certificate to site: {bindingInfo.SiteName}." + }; } } catch (Exception ex) { @@ -183,7 +197,7 @@ public JobResult ProcessJob(ManagementJobConfiguration config) }; } - _logger.LogTrace($"Completed adding and binding the certificate to the store"); + _logger.LogTrace($"Exiting the Adding of Certificate process."); break; } @@ -284,9 +298,10 @@ public string AddCertificate(string certificateContents, string privateKeyPasswo catch (Exception ex) { var failureMessage = $"Management job {_operationType} failed on Store '{_storePath}' on server '{_clientMachineName}' with error: '{LogHandler.FlattenException(ex)}'"; + var niceMessage = $"Management job {_operationType} failed on Store '{_storePath}' on server '{_clientMachineName}' with error: {ex.Message}"; _logger.LogError(failureMessage); - throw new Exception (failureMessage); + throw new Exception (niceMessage); } } public void RemoveIISCertificate(string thumbprint) diff --git a/IISU/ImplementedStoreTypes/WinIIS/WinIISBinding.cs b/IISU/ImplementedStoreTypes/WinIIS/WinIISBinding.cs index 54b18a2..678a2b4 100644 --- a/IISU/ImplementedStoreTypes/WinIIS/WinIISBinding.cs +++ b/IISU/ImplementedStoreTypes/WinIIS/WinIISBinding.cs @@ -14,6 +14,8 @@ // 021225 rcp 2.6.0 Cleaned up and verified code +// Ignore Spelling: Keyfactor IISU + using Keyfactor.Logging; using Microsoft.Extensions.Logging; using System; @@ -25,9 +27,9 @@ namespace Keyfactor.Extensions.Orchestrator.WindowsCertStore.IISU { public class WinIISBinding { - private static ILogger _logger; - private static Collection? _results = null; - private static PSHelper _helper; +#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. + private static ILogger? _logger; +#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. public static Collection BindCertificate(PSHelper psHelper, IISBindingInfo bindingInfo, string thumbprint, string renewalThumbprint, string storePath) { diff --git a/IISU/ImplementedStoreTypes/WinSQL/Inventory.cs b/IISU/ImplementedStoreTypes/WinSQL/Inventory.cs index eb50428..7402f97 100644 --- a/IISU/ImplementedStoreTypes/WinSQL/Inventory.cs +++ b/IISU/ImplementedStoreTypes/WinSQL/Inventory.cs @@ -35,7 +35,9 @@ public class Inventory : WinCertJobTypeBase, IInventoryJobExtension private ILogger _logger; public string ExtensionName => "WinSqlInventory"; +#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. Collection? results = null; +#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. public Inventory() { diff --git a/IISU/ImplementedStoreTypes/WinSQL/Management.cs b/IISU/ImplementedStoreTypes/WinSQL/Management.cs index e5b1470..2499dc5 100644 --- a/IISU/ImplementedStoreTypes/WinSQL/Management.cs +++ b/IISU/ImplementedStoreTypes/WinSQL/Management.cs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Ignore Spelling: thumbprint Keyfactor sql +// Ignore Spelling: thumbprint Keyfactor sql crypto // 021225 rcp 2.6.0 Cleaned up and verified code @@ -35,7 +35,9 @@ public class Management : WinCertJobTypeBase, IManagementJobExtension private ILogger _logger; private PSHelper _psHelper; +#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. private Collection? _results = null; +#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. // Function wide config values private string _clientMachineName = string.Empty; @@ -172,8 +174,6 @@ public JobResult ProcessJob(ManagementJobConfiguration config) // Remove the certificate from the cert store complete = RemoveCertificate(config.JobCertificate.Alias); _logger.LogTrace($"Completed removing the certificate from the store"); - - break; } else { @@ -184,7 +184,6 @@ public JobResult ProcessJob(ManagementJobConfiguration config) FailureMessage = "Unable to unbind one or more certificates from the SQL Instances." }; } - } catch (Exception ex) { @@ -195,10 +194,9 @@ public JobResult ProcessJob(ManagementJobConfiguration config) FailureMessage = ex.Message }; } - - _logger.LogTrace($"Completed unbinding and removing the certificate from the store"); - return complete; } + _logger.LogTrace($"Completed unbinding and removing the certificate from the store"); + return complete; } } diff --git a/IISU/ImplementedStoreTypes/WinSQL/WinSqlBinding.cs b/IISU/ImplementedStoreTypes/WinSQL/WinSqlBinding.cs index 2a0be33..673f7b1 100644 --- a/IISU/ImplementedStoreTypes/WinSQL/WinSqlBinding.cs +++ b/IISU/ImplementedStoreTypes/WinSQL/WinSqlBinding.cs @@ -28,7 +28,9 @@ namespace Keyfactor.Extensions.Orchestrator.WindowsCertStore.WinSql public class WinSqlBinding { private static ILogger _logger; +#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. private static Collection? _results = null; +#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. public WinSqlBinding() { diff --git a/IISU/PSHelper.cs b/IISU/PSHelper.cs index 8bc56fb..498a9ec 100644 --- a/IISU/PSHelper.cs +++ b/IISU/PSHelper.cs @@ -14,6 +14,8 @@ // 021225 rcp 2.6.0 Cleaned up and verified code +// Ignore Spelling: Keyfactor + using Keyfactor.Logging; using Microsoft.Extensions.Logging; using System; @@ -47,7 +49,9 @@ public class PSHelper : IDisposable private string port; private bool useSPN; private string machineName; +#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. private string? argument; +#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. private string serverUserName; private string serverPassword; @@ -185,9 +189,6 @@ private void InitializeRemoteSession() _logger.LogTrace("Initializing WinRM connection"); try { - var pw = new NetworkCredential(serverUserName, serverPassword).SecurePassword; - PSCredential myCreds = new PSCredential(serverUserName, pw); - // Create the PSSessionOption object var sessionOption = new PSSessionOption { @@ -197,8 +198,22 @@ private void InitializeRemoteSession() PS.AddCommand("New-PSSession") .AddParameter("ComputerName", ClientMachineName) .AddParameter("Port", port) - .AddParameter("Credential", myCreds) .AddParameter("SessionOption", sessionOption); + + if (protocol == "https") + { + _logger.LogTrace($"Using HTTPS to connect to: {clientMachineName}"); + PS.AddParameter("UseSSL"); + } + + if (!string.IsNullOrEmpty(serverUserName)) + { + var pw = new NetworkCredential(serverUserName, serverPassword).SecurePassword; + PSCredential myCreds = new PSCredential(serverUserName, pw); + + PS.AddParameter("Credential", myCreds); + } + } catch (Exception) { @@ -235,6 +250,12 @@ private void InitializeRemoteSession() private void InitializeLocalSession() { + _logger.LogTrace("Creating out-of-process Powershell Runspace."); + PowerShellProcessInstance psInstance = new PowerShellProcessInstance(new Version(5, 1), null, null, false); + Runspace rs = RunspaceFactory.CreateOutOfProcessRunspace(new TypeTable(Array.Empty()), psInstance); + rs.Open(); + PS.Runspace = rs; + _logger.LogTrace("Setting Execution Policy to Unrestricted"); PS.AddScript("Set-ExecutionPolicy Unrestricted -Scope Process -Force"); PS.Invoke(); // Ensure the script is invoked and loaded @@ -242,13 +263,6 @@ private void InitializeLocalSession() PS.Commands.Clear(); // Clear commands after loading functions - // Trying this to get IISAdministration loaded!! - PowerShellProcessInstance psInstance = new PowerShellProcessInstance(new Version(5, 1), null, null, false); - Runspace rs = RunspaceFactory.CreateOutOfProcessRunspace(new TypeTable(Array.Empty()), psInstance); - rs.Open(); - - PS.Runspace = rs; - _logger.LogTrace("Setting script file into memory"); PS.AddScript(". '" + scriptFileLocation + "'"); PS.Invoke(); // Ensure the script is invoked and loaded @@ -297,7 +311,9 @@ public void Terminate() PS.Dispose(); } +#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. public Collection? InvokeFunction(string functionName, Dictionary? parameters = null) +#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. { PS.Commands.Clear(); @@ -335,7 +351,9 @@ public Collection ExecutePowerShellScript(string script) } +#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. public Collection? ExecutePowerShell(string commandOrScript, Dictionary? parameters = null, bool isScript = false) +#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. { try { @@ -478,7 +496,9 @@ private static string FindPSLocation(string directory, string fileName) return null; } +#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. public static void ProcessPowerShellScriptEvent(object? sender, DataAddedEventArgs e) +#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. { if (sender != null) { diff --git a/IISU/PowerShellScripts/WinCertScripts.ps1 b/IISU/PowerShellScripts/WinCertScripts.ps1 index 62b0466..a77dccf 100644 --- a/IISU/PowerShellScripts/WinCertScripts.ps1 +++ b/IISU/PowerShellScripts/WinCertScripts.ps1 @@ -185,97 +185,101 @@ function Get-KFIISBoundCertificates { } } -function Get-KFIISBoundCertificatesORIG { - # Import the IISAdministration module - Import-Module IISAdministration - - # Get all websites - $websites = Get-IISSite - - # Write the count of websites found - Write-Information "There were $($websites.Count) websites found." +function Add-KFCertificateToStore{ + param ( + [Parameter(Mandatory = $true)] + [string]$Base64Cert, + + [Parameter(Mandatory = $false)] + [string]$PrivateKeyPassword, + + [Parameter(Mandatory = $true)] + [string]$StoreName, + + [Parameter(Mandatory = $false)] + [string]$CryptoServiceProvider + ) - # Initialize an array to store the results - $certificates = @() + try { + Write-Information "Entering PowerShell Script Add-KFCertificate" + Write-Verbose "Add-KFCertificateToStore - Received: StoreName: '$StoreName', CryptoServiceProvider: '$CryptoServiceProvider', Base64Cert: '$Base64Cert'" - # Initialize a counter for the total number of bindings with certificates - $totalBoundCertificates = 0 + $thumbprint = $null - foreach ($site in $websites) { - # Get the site name - $siteName = $site.name + if ($CryptoServiceProvider) + { + # Test to see if CSP exists + if(-not (Test-CryptoServiceProvider -CSPName $CryptoServiceProvider)) + { + Write-Information "INFO: The CSP $CryptoServiceProvider was not found on the system." + Write-Warning "WARN: CSP $CryptoServiceProvider was not found on the system." + return + } - # Get the bindings for the site - $bindings = Get-IISSiteBinding -Name $siteName + Write-Information "Adding certificate with the CSP '$CryptoServiceProvider'" - # Initialize a counter for bindings with certificates for the current site - $siteBoundCertificateCount = 0 + # Create temporary file for the PFX + $tempPfx = [System.IO.Path]::GetTempFileName() + ".pfx" + [System.IO.File]::WriteAllBytes($tempPfx, [Convert]::FromBase64String($Base64Cert)) - foreach ($binding in $bindings) { - # Check if the binding has an SSL certificate - if ($binding.protocol -eq 'https' -and $binding.RawAttributes.certificateHash) { - # Get the certificate hash - $certHash = $binding.RawAttributes.certificateHash - # Get the certificate store - $StoreName = $binding.certificateStoreName + # Execute certutil based on whether a private key password was supplied + try { + # Build certutil command to import the certificate with exportable private key and CSP + $command = "certutil -f -p `"$PrivateKeyPassword`" -csp `"$CryptoServiceProvider`" -importpfx $StoreName `"$tempPfx`"" + $traceCommand = "certutil -f -p `"************`" -csp `"$CryptoServiceProvider`" -importpfx $StoreName `"$tempPfx`"" - try { - # Get the certificate details from the certificate store - $cert = Get-ChildItem -Path "Cert:\LocalMachine\$StoreName\$certHash" + Write-Verbose "Running: $traceCommand" + $output = Invoke-Expression $command - # Convert certificate data to Base64 - $certBase64 = [Convert]::ToBase64String($cert.RawData) + if ($LASTEXITCODE -ne 0) { + throw "certutil failed with code $LASTEXITCODE. `nOutput: $output `nMake sure there is no cryptographic mismatch and the CSP supports the imported PFX.`n" + } - # Create a custom object to store the results - $certInfo = [PSCustomObject]@{ - SiteName = $siteName - Binding = $binding.bindingInformation - IPAddress = ($binding.bindingInformation -split ":")[0] - Port = ($binding.bindingInformation -split ":")[1] - Hostname = ($binding.bindingInformation -split ":")[2] - Protocol = $binding.protocol - SNI = $binding.sslFlags -eq 1 - ProviderName = Get-CertificateCSP $cert - SAN = Get-KFSAN $cert - Certificate = $cert.Subject - ExpiryDate = $cert.NotAfter - Issuer = $cert.Issuer - Thumbprint = $cert.Thumbprint - HasPrivateKey = $cert.HasPrivateKey - CertificateBase64 = $certBase64 - } + # Get latest cert with private key in the store + $store = "Cert:\LocalMachine\$StoreName" + $cert = Get-ChildItem -Path $store | Where-Object { $_.HasPrivateKey } | Sort-Object NotBefore -Descending | Select-Object -First 1 - # Add the certificate information to the array - $certificates += $certInfo + if ($cert) { + Write-Information "Certificate imported successfully with Thumbprint: $($cert.Thumbprint)" + return $cert.Thumbprint + } else { + throw "Import succeeded, but no certificate with a private key was found in $store" + } - # Increment the counters - $siteBoundCertificateCount++ - $totalBoundCertificates++ - } catch { - Write-Warning "Could not retrieve certificate details for hash $certHash in store $StoreName." - Write-Warning $_ - + } catch { + Write-Error "ERROR: $_" + } finally { + if (Test-Path $tempPfx) { + #Remove-Item $tempPfx -Force } } - } - # Write the count of bindings with certificates for the current site - Write-Information "Website: $siteName has $siteBoundCertificateCount bindings with certificates." - } + } else { + $bytes = [System.Convert]::FromBase64String($Base64Cert) + $certStore = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Store -ArgumentList $storeName, "LocalMachine" + Write-Information "Store '$StoreName' is open." + $certStore.Open(5) - # Write the total count of bindings with certificates - Write-Information "A total of $totalBoundCertificates bindings with valid certificates were found." + $cert = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList $bytes, $PrivateKeyPassword, 18 <# Persist, Machine #> + $certStore.Add($cert) + $certStore.Close(); + Write-Information "Store '$StoreName' is closed." - # Output the results in JSON format or indicate no certificates found - if ($totalBoundCertificates -gt 0) { - $certificates | ConvertTo-Json - } else { - Write-Information "No valid certificates were found bound to websites." + # Get the thumbprint so it can be returned to the calling function + $thumbprint = $cert.Thumbprint + Write-Information "The thumbprint '$thumbprint' was created." + } + + Write-Host "Certificate added successfully to $StoreName." + return $thumbprint + } catch { + Write-Error "An error occurred: $_" + return $null } } -function Add-KFCertificateToStore{ +function Add-KFCertificateToStoreNEW{ param ( [Parameter(Mandatory = $true)] [string]$Base64Cert, @@ -308,58 +312,49 @@ function Add-KFCertificateToStore{ Write-Information "Adding certificate with the CSP '$CryptoServiceProvider'" - # Write certificate to a temporary PFX file - $tempFileName = [System.IO.Path]::GetTempFileName() + '.pfx' - [System.IO.File]::WriteAllBytes($tempFileName, [System.Convert]::FromBase64String($Base64Cert)) - - # Initialize output variable - $output = "" + # Convert Base64 PFX to bytes and save to temp file + $tempPfxPath = [System.IO.Path]::GetTempFileName() + ".pfx" + [System.IO.File]::WriteAllBytes($tempPfxPath, [Convert]::FromBase64String($Base64Cert)) - # Execute certutil based on whether a private key password was supplied try { - # Generate the appropriate certutil command based on the parameters - $cryptoProviderPart = if ($CryptoServiceProvider) { "-csp `"$CryptoServiceProvider`" " } else { "" } - $passwordPart = if ($PrivateKeyPassword) { "-p `"$PrivateKeyPassword`" " } else { "" } - $action = if ($PrivateKeyPassword) { "importpfx" } else { "addstore" } - - # Construct the full certutil command - $command = "certutil -f $cryptoProviderPart$passwordPart-$action $StorePath `"$tempFileName`"" - $output = Invoke-Expression $command - - # Check for errors based on the last exit code - if ($LASTEXITCODE -ne 0) { - throw "Certutil failed with exit code $LASTEXITCODE. Output: $output" - } - - # Additional check for known error keywords in output (optional) - if ($output -match "(ERROR|FAILED|EXCEPTION)") { - throw "Certutil output indicates an error: $output" - } - - # Retrieve the certificate thumbprint from the store - $cert = Get-ChildItem -Path "Cert:\LocalMachine\$StoreName" | Sort-Object -Property NotAfter -Descending | Select-Object -First 1 - if ($cert) { - $output = $cert.Thumbprint - Write-Output "Certificate imported successfully. Thumbprint: $thumbprint" - } - else { - throw "Certificate import succeeded, but no certificate was found in the $StoreName store." + # Load the PFX into a PKCS12 object + $pfx = New-Object -ComObject X509Enrollment.CX509Enrollment + $pfx.InitializeImport(1, [System.IO.File]::ReadAllText($tempPfxPath), $PrivateKeyPassword) + + # Create new private key with desired CSP + $privateKey = New-Object -ComObject X509Enrollment.CX509PrivateKey + $privateKey.ProviderName = $CryptoServiceProvider + $privateKey.Length = [int]2048 + $privateKey.KeySpec = 1 # AT_KEYEXCHANGE + $privateKey.ExportPolicy = 1 # AllowExport + $privateKey.MachineContext = $true + $privateKey.Create() + + # Associate private key with enrollment + $pfx.InstallResponse(2, "", 0, $null) + + Write-Host "Certificate imported successfully using CSP: $CryptoServiceProvider" + + # The most recently added cert (with private key) should be the new one + $latest = $certsBefore | Where-Object { $_.HasPrivateKey } | Sort-Object NotBefore -Descending | Select-Object -First 1 + + if ($latest) { + Write-Information "Certificate imported successfully with thumbprint: $($latest.Thumbprint)" + return $latest.Thumbprint + } else { + throw "Certificate installed but no cert with private key was found in store '$StoreName'." } } catch { # Handle any errors and log the exception message Write-Error "Error during certificate import: $_" - $output = "Error: $_" + return "Error: $_" } finally { # Ensure the temporary file is deleted if (Test-Path $tempFileName) { Remove-Item $tempFileName -Force } } - - # Output the final result - return $output - } else { $bytes = [System.Convert]::FromBase64String($Base64Cert) $certStore = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Store -ArgumentList $storeName, "LocalMachine" @@ -383,7 +378,6 @@ function Add-KFCertificateToStore{ return $null } } - function Remove-KFCertificateFromStore { param ( [string]$Thumbprint, @@ -437,267 +431,6 @@ function Remove-KFCertificateFromStore { return $isSuccessful } -function New-KFIISSiteBindingV1 { - [CmdletBinding()] - [OutputType([pscustomobject])] - param ( - [Parameter(Mandatory = $true)] - [string]$SiteName, - [string]$IPAddress = "*", - [int]$Port = 443, - [string]$Hostname = "", - [ValidateSet("http", "https")] - [string]$Protocol = "https", - [string]$Thumbprint, - [string]$StoreName = "My", - [int]$SslFlags = 0 - ) - - Write-Information "Entering PowerShell Script: New-KFIISSiteBinding" -InformationAction SilentlyContinue - Write-Verbose "Entered New-KFIISSiteBinding with values SiteName: '$SiteName', IPAddress: '$IPAddress', Port: $Port, HostName: '$Hostname', Protocol: '$Protocol', Thumbprint: '$Thumbprint', Store Path: '$StoreName', SslFlags: '$SslFlags'" - - # Check for existing binding conflict - $conflict = CheckExistingBindings -DesiredIP $IPAddress -DesiredPort $Port -DesiredHost $Hostname -TargetSiteName $SiteName - - if ($conflict) { - $msg = "A Binding Conflict was detected. Skipping binding for site '$SiteName'." - Write-Warning $msg -InformationAction SilentlyContinue - return New-ResultObject -Status Skipped -Code 100 -Step CheckBinding -Message $msg -Details @{ SiteName = $SiteName; IPAddress = $IPAddress; Port = $Port; HostName = $Hostname } - } - - $searchBindings = "${IPAddress}:${Port}:${Hostname}" - $hasIISDrive = Ensure-IISDrive - Write-Verbose "IIS Drive is available: $hasIISDrive" - - if ($hasIISDrive) { - Import-Module WebAdministration - $sitePath = "IIS:\Sites\$SiteName" - if (-not (Test-Path $sitePath)) { - $msg = "Site '$SiteName' not found in IIS drive." - Write-Error $msg -InformationAction SilentlyContinue - return New-ResultObject -Status Error -Code 201 -Step FindWebSite -Message $msg -Details @{ SiteName = $SiteName; IPAddress = $IPAddress; Port = $Port; HostName = $Hostname } - } - - $site = Get-Item $sitePath - $httpsBindings = $site.Bindings.Collection | Where-Object { - $_.bindingInformation -eq $searchBindings -and $_.protocol -eq "https" - } - - # Step 2: Remove existing binding(s) - foreach ($binding in $httpsBindings) { - try { - Write-Verbose "Calling Remove-WebBinding -Name $SiteName -BindingInformation $binding.bindingInformation -Protocol $binding.protocol -Confirm:$false" - Remove-WebBinding -Name $SiteName -BindingInformation $binding.bindingInformation -Protocol $binding.protocol -Confirm:$false - } catch { - $msg = "Error removing binding '$($binding.bindingInformation)': $_" - Write-Warning $msg -InformationAction SilentlyContinue - return New-ResultObject -Status Error -Code 201 -Step RemoveBinding -ErrorMessage $msg - } - } - - # Step 3: Add new binding - try { - Write-Verbose "Calling New-WebBinding -Name $SiteName -Protocol $Protocol -IPAddress $IPAddress -Port $Port -HostHeader '$Hostname' -SslFlags $SslFlags" - New-WebBinding -Name $SiteName -Protocol $Protocol -IPAddress $IPAddress -Port $Port -HostHeader $Hostname -SslFlags $SslFlags - } catch { - $msg = "Error adding binding: $_" - Write-Warning $msg -InformationAction SilentlyContinue - return New-ResultObject -Status Error -Code 202 -Step AddBinding -ErrorMessage $msg - } - - # Step 4: Bind SSL certificate - Write-Verbose "Calling Get-WebBinding -Name $SiteName -Protocol $Protocol, Where BindingInformation equals '$searchBindings'" - $binding = Get-WebBinding -Name $SiteName -Protocol $Protocol | Where-Object { - $_.bindingInformation -eq $searchBindings - } - - if ($binding) { - Write-Verbose "Binding thumbprint $thumbprint to $binding.bindingInformation in store: $StoreName" - $binding.AddSslCertificate($Thumbprint, $StoreName) - return New-ResultObject -Status Success -Code 0 -Step BindSSL - } else { - return New-ResultObject -Status Error -Code 202 -Step BindSSL -Message "No binding found for: $searchBindings" - } - - } else { - # SERVERMANAGER FALLBACK - Add-Type -Path "$env:windir\System32\inetsrv\Microsoft.Web.Administration.dll" - $iis = New-Object Microsoft.Web.Administration.ServerManager - $site = $iis.Sites[$SiteName] - - if ($null -eq $site) { - $msg = "Site '$SiteName' not found in ServerManager." - Write-Error $msg -InformationAction SilentlyContinue - return New-ResultObject -Status Error -Code 201 -Step FindWebSite -Message $msg -Details @{ SiteName = $SiteName; IPAddress = $IPAddress; Port = $Port; HostName = $Hostname } - } - - $httpsBindings = $site.Bindings | Where-Object { - $_.bindingInformation -eq $searchBindings -and $_.protocol -eq "https" - } - - # Step 2: Remove existing bindings - foreach ($binding in $httpsBindings) { - try { - $site.Bindings.Remove($binding) - } catch { - $msg = "Error removing binding: $_" - Write-Warning $msg -InformationAction SilentlyContinue - return New-ResultObject -Status Error -Code 201 -Step RemoveBinding -ErrorMessage $msg - } - } - - # Step 3: Add new binding - $cleanThumbprint = $Thumbprint -replace '[^a-fA-F0-9]', '' - $hashBytes = -split $cleanThumbprint -replace '..', '$& ' -split ' ' | Where-Object { $_ -ne '' } | ForEach-Object { [Convert]::ToByte($_, 16) } - - try { - $newBinding = $site.Bindings.Add($searchBindings, $Protocol) - if ($Protocol -eq "https") { - $newBinding.CertificateStoreName = $StoreName - $newBinding.CertificateHash = [byte[]]$hashBytes - $newBinding.SetAttributeValue("sslFlags", $SslFlags) - } - $iis.CommitChanges() - return New-ResultObject -Status Success -Code 0 -Step BindSSL -Message "Binding and certificate successfully applied via ServerManager." - } catch { - $msg = "Error adding binding: $_" - Write-Warning $msg -InformationAction SilentlyContinue - return New-ResultObject -Status Error -Code 202 -Step BindSSL -ErrorMessage $msg - } - } -} - -function New-KFIISSiteBindingV2 { - [CmdletBinding()] - [OutputType([pscustomobject])] - param ( - [Parameter(Mandatory = $true)] - [string]$SiteName, - [string]$IPAddress = "*", - [int]$Port = 443, - [string]$Hostname = "", - [ValidateSet("http", "https")] - [string]$Protocol = "https", - [string]$Thumbprint, - [string]$StoreName = "My", - [int]$SslFlags = 0 - ) - - Write-Information "Entering PowerShell Script: New-KFIISSiteBinding" -InformationAction SilentlyContinue - Write-Verbose "Entered New-KFIISSiteBinding with values SiteName: '$SiteName', IPAddress: '$IPAddress', Port: $Port, HostName: '$Hostname', Protocol: '$Protocol', Thumbprint: '$Thumbprint', Store Path: '$StoreName', SslFlags: '$SslFlags'" - - $result = $null - - # Check for existing binding conflict - $conflict = CheckExistingBindings -DesiredIP $IPAddress -DesiredPort $Port -DesiredHost $Hostname -TargetSiteName $SiteName - if ($conflict) { - $msg = "A Binding Conflict was detected. Skipping binding for site '$SiteName'." - Write-Warning $msg -InformationAction SilentlyContinue - $result = New-ResultObject -Status Skipped -Code 100 -Step CheckBinding -Message $msg -Details @{ SiteName = $SiteName; IPAddress = $IPAddress; Port = $Port; HostName = $Hostname } - return $result - } - - $searchBindings = "${IPAddress}:${Port}:${Hostname}" - $hasIISDrive = Ensure-IISDrive - Write-Verbose "IIS Drive is available: $hasIISDrive" - - if ($hasIISDrive) { - Import-Module WebAdministration - $sitePath = "IIS:\Sites\$SiteName" - if (-not (Test-Path $sitePath)) { - $msg = "Site '$SiteName' not found in IIS drive." - Write-Error $msg -InformationAction SilentlyContinue - $result = New-ResultObject -Status Error -Code 201 -Step FindWebSite -Message $msg -Details @{ SiteName = $SiteName; IPAddress = $IPAddress; Port = $Port; HostName = $Hostname } - } else { - $site = Get-Item $sitePath - $httpsBindings = $site.Bindings.Collection | Where-Object { - $_.bindingInformation -eq $searchBindings -and $_.protocol -eq "https" - } - - foreach ($binding in $httpsBindings) { - try { - Write-Verbose "Calling Remove-WebBinding -Name $SiteName -BindingInformation $binding.bindingInformation -Protocol $binding.protocol -Confirm:$false" - Remove-WebBinding -Name $SiteName -BindingInformation $binding.bindingInformation -Protocol $binding.protocol -Confirm:$false - } catch { - $msg = "Error removing binding '$($binding.bindingInformation)': $_" - Write-Warning $msg -InformationAction SilentlyContinue - $result = New-ResultObject -Status Error -Code 201 -Step RemoveBinding -ErrorMessage $msg - return $result - } - } - - try { - Write-Verbose "Calling New-WebBinding -Name $SiteName -Protocol $Protocol -IPAddress $IPAddress -Port $Port -HostHeader '$Hostname' -SslFlags $SslFlags" - New-WebBinding -Name $SiteName -Protocol $Protocol -IPAddress $IPAddress -Port $Port -HostHeader $Hostname -SslFlags $SslFlags - } catch { - $msg = "Error adding binding: $_" - Write-Warning $msg -InformationAction SilentlyContinue - $result = New-ResultObject -Status Error -Code 202 -Step AddBinding -ErrorMessage $msg - return $result - } - - Write-Verbose "Calling Get-WebBinding -Name $SiteName -Protocol $Protocol, Where BindingInformation equals '$searchBindings'" - $binding = Get-WebBinding -Name $SiteName -Protocol $Protocol | Where-Object { - $_.bindingInformation -eq $searchBindings - } - - if ($binding) { - Write-Verbose "Binding thumbprint $thumbprint to $binding.bindingInformation in store: $StoreName" - $null = $binding.AddSslCertificate($Thumbprint, $StoreName) - $result = New-ResultObject -Status Success -Code 0 -Step BindSSL - } else { - $result = New-ResultObject -Status Error -Code 202 -Step BindSSL -Message "No binding found for: $searchBindings" - } - } - } else { - # SERVERMANAGER FALLBACK - Add-Type -Path "$env:windir\System32\inetsrv\Microsoft.Web.Administration.dll" - $iis = New-Object Microsoft.Web.Administration.ServerManager - $site = $iis.Sites[$SiteName] - - if ($null -eq $site) { - $msg = "Site '$SiteName' not found in ServerManager." - Write-Error $msg -InformationAction SilentlyContinue - $result = New-ResultObject -Status Error -Code 201 -Step FindWebSite -Message $msg -Details @{ SiteName = $SiteName; IPAddress = $IPAddress; Port = $Port; HostName = $Hostname } - } else { - $httpsBindings = $site.Bindings | Where-Object { - $_.bindingInformation -eq $searchBindings -and $_.protocol -eq "https" - } - - foreach ($binding in $httpsBindings) { - try { - $site.Bindings.Remove($binding) - } catch { - $msg = "Error removing binding: $_" - Write-Warning $msg -InformationAction SilentlyContinue - $result = New-ResultObject -Status Error -Code 201 -Step RemoveBinding -ErrorMessage $msg - return $result - } - } - - $cleanThumbprint = $Thumbprint -replace '[^a-fA-F0-9]', '' - $hashBytes = -split $cleanThumbprint -replace '..', '$& ' -split ' ' | Where-Object { $_ -ne '' } | ForEach-Object { [Convert]::ToByte($_, 16) } - - try { - $newBinding = $site.Bindings.Add($searchBindings, $Protocol) - if ($Protocol -eq "https") { - $newBinding.CertificateStoreName = $StoreName - $newBinding.CertificateHash = [byte[]]$hashBytes - $newBinding.SetAttributeValue("sslFlags", $SslFlags) - } - $iis.CommitChanges() - $result = New-ResultObject -Status Success -Code 0 -Step BindSSL -Message "Binding and certificate successfully applied via ServerManager." - } catch { - $msg = "Error adding binding: $_" - Write-Warning $msg -InformationAction SilentlyContinue - $result = New-ResultObject -Status Error -Code 202 -Step BindSSL -ErrorMessage $msg - } - } - } - - return $result -} - function New-KFIISSiteBinding { [CmdletBinding()] [OutputType([pscustomobject])] @@ -1584,24 +1317,11 @@ function Test-CryptoServiceProvider { [string]$CSPName ) - # Function to get the list of installed Cryptographic Service Providers from the registry - function Get-CryptoServiceProviders { - $cspRegistryPath = "HKLM:\SOFTWARE\Microsoft\Cryptography\Defaults\Provider" - - # Retrieve all CSP names from the registry - $providers = Get-ChildItem -Path $cspRegistryPath | Select-Object -ExpandProperty PSChildName - - return $providers - } - - # Get the list of installed CSPs - $installedCSPs = Get-CryptoServiceProviders - - # Check if the user-provided CSP exists in the list - if ($installedCSPs -contains $CSPName) { + try { + Validate-CryptoProvider -ProviderName $CSPName -Verbose:$false return $true } - else { + catch { return $false } } @@ -1616,18 +1336,25 @@ function Get-CertificateCSP { # Check if the certificate has a private key if ($Cert -and $Cert.HasPrivateKey) { try { - # Access the certificate's private key to get CSP info $key = $Cert.PrivateKey - # Retrieve the Provider Name from the private key - $cspName = $key.Key.Provider.Provider - - # Return the CSP name - return $cspName + if ($key -is [System.Security.Cryptography.RSACryptoServiceProvider]) { + # CAPI-based key + return $key.CspKeyContainerInfo.ProviderName + } + elseif ($key -is [System.Security.Cryptography.RSACng]) { + # CNG-based key + return $key.Key.Provider + } + else { + return "Unknown provider type: $($key.GetType().FullName)" + } } catch { + Write-Warning "Could not access provider information: $_" return $null } } else { + Write-Warning "Certificate has no private key." return $null } } @@ -1669,7 +1396,8 @@ function Validate-CryptoProvider { $availableProviders = Get-CryptoProviders - if (-not ($availableProviders -contains $ProviderName)) { + if (-not ($availableProviders | Where-Object { $_.Trim().ToLowerInvariant() -eq $ProviderName.Trim().ToLowerInvariant() })) { + throw "Crypto Service Provider '$ProviderName' is either invalid or not found on this system." } diff --git a/IISU/WindowsCertStore.csproj b/IISU/WindowsCertStore.csproj index 6433408..93795e3 100644 --- a/IISU/WindowsCertStore.csproj +++ b/IISU/WindowsCertStore.csproj @@ -34,11 +34,16 @@ - + - - - + + + + + + + + diff --git a/README.md b/README.md index bdb10bb..3a5e085 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,7 @@ For customers wishing to use something other than the local administrator accoun ## Certificate Store Types -To use the Windows Certificate Universal Orchestrator extension, you **must** create the Certificate Store Types required for your usecase. This only needs to happen _once_ per Keyfactor Command instance. +To use the Windows Certificate Universal Orchestrator extension, you **must** create the Certificate Store Types required for your use-case. This only needs to happen _once_ per Keyfactor Command instance. The Windows Certificate Universal Orchestrator extension implements 3 Certificate Store Types. Depending on your use case, you may elect to use one, or all of these Certificate Store Types. @@ -160,6 +160,8 @@ The store type represents the various certificate stores present on a Windows Se - **Limitations:** Users should be aware that for this store type to function correctly, certain permissions are necessary. While some advanced users successfully use non-administrator accounts with specific permissions, it is officially supported only with Local Administrator permissions. Complexities with interactions between Group Policy, WinRM, User Account Control, and other environmental factors may impede operations if not properly configured. + + #### Supported Operations | Operation | Is Supported | @@ -173,7 +175,7 @@ The store type represents the various certificate stores present on a Windows Se #### Store Type Creation ##### Using kfutil: -`kfutil` is a custom CLI for the Keyfactor Command API and can be used to created certificate store types. +`kfutil` is a custom CLI for the Keyfactor Command API and can be used to create certificate store types. For more information on [kfutil](https://github.com/Keyfactor/kfutil) check out the [docs](https://github.com/Keyfactor/kfutil?tab=readme-ov-file#quickstart)
Click to expand WinCert kfutil details @@ -270,7 +272,7 @@ the Keyfactor Command Portal
Click to expand details -The IIS Bound Certificate Certificate Store Type, identified by its short name 'IISU,' is designed for the management of certificates bound to IIS (Internet Information Services) servers. This store type allows users to automate and streamline the process of adding, removing, and reenrolling certificates for IIS sites, making it significantly easier to manage web server certificates. +The IIS Bound Certificate Store Type, identified by its short name 'IISU,' is designed for the management of certificates bound to IIS (Internet Information Services) servers. This store type allows users to automate and streamline the process of adding, removing, and reenrolling certificates for IIS sites, making it significantly easier to manage web server certificates. #### Key Features and Representation @@ -287,6 +289,8 @@ The IISU store type represents the IIS servers and their certificate bindings. I - **Custom Alias and Private Keys:** The store type does not support custom aliases for individual entries and requires private keys because IIS certificates without private keys would be invalid. + + #### Supported Operations | Operation | Is Supported | @@ -300,7 +304,7 @@ The IISU store type represents the IIS servers and their certificate bindings. I #### Store Type Creation ##### Using kfutil: -`kfutil` is a custom CLI for the Keyfactor Command API and can be used to created certificate store types. +`kfutil` is a custom CLI for the Keyfactor Command API and can be used to create certificate store types. For more information on [kfutil](https://github.com/Keyfactor/kfutil) check out the [docs](https://github.com/Keyfactor/kfutil?tab=readme-ov-file#quickstart)
Click to expand IISU kfutil details @@ -412,6 +416,8 @@ The WinSql Certificate Store Type, referred to by its short name 'WinSql,' is de - **Limitations:** Users should be aware that for this store type to function correctly, certain permissions are necessary. While some advanced users successfully use non-administrator accounts with specific permissions, it is officially supported only with Local Administrator permissions. Complexities with interactions between Group Policy, WinRM, User Account Control, and other environmental factors may impede operations if not properly configured. + + #### Supported Operations | Operation | Is Supported | @@ -425,7 +431,7 @@ The WinSql Certificate Store Type, referred to by its short name 'WinSql,' is de #### Store Type Creation ##### Using kfutil: -`kfutil` is a custom CLI for the Keyfactor Command API and can be used to created certificate store types. +`kfutil` is a custom CLI for the Keyfactor Command API and can be used to create certificate store types. For more information on [kfutil](https://github.com/Keyfactor/kfutil) check out the [docs](https://github.com/Keyfactor/kfutil?tab=readme-ov-file#quickstart)
Click to expand WinSql kfutil details @@ -657,12 +663,9 @@ Please refer to the **Universal Orchestrator (remote)** usage section ([PAM prov
- > The content in this section can be supplemented by the [official Command documentation](https://software.keyfactor.com/Core-OnPrem/Current/Content/ReferenceGuide/Certificate%20Stores.htm?Highlight=certificate%20store). - -
IIS Bound Certificate (IISU) @@ -752,12 +755,9 @@ Please refer to the **Universal Orchestrator (remote)** usage section ([PAM prov
- > The content in this section can be supplemented by the [official Command documentation](https://software.keyfactor.com/Core-OnPrem/Current/Content/ReferenceGuide/Certificate%20Stores.htm?Highlight=certificate%20store). - -
WinSql (WinSql) @@ -849,12 +849,9 @@ Please refer to the **Universal Orchestrator (remote)** usage section ([PAM prov
- > The content in this section can be supplemented by the [official Command documentation](https://software.keyfactor.com/Core-OnPrem/Current/Content/ReferenceGuide/Certificate%20Stores.htm?Highlight=certificate%20store). - -
diff --git a/WinCertTestConsole/WinCertTestConsole.csproj b/WinCertTestConsole/WinCertTestConsole.csproj index 0599b3b..26c2492 100644 --- a/WinCertTestConsole/WinCertTestConsole.csproj +++ b/WinCertTestConsole/WinCertTestConsole.csproj @@ -8,7 +8,7 @@ - + diff --git a/docsource/iisu.md b/docsource/iisu.md index 8d549bf..7a9c800 100644 --- a/docsource/iisu.md +++ b/docsource/iisu.md @@ -1,6 +1,6 @@ ## Overview -The IIS Bound Certificate Certificate Store Type, identified by its short name 'IISU,' is designed for the management of certificates bound to IIS (Internet Information Services) servers. This store type allows users to automate and streamline the process of adding, removing, and reenrolling certificates for IIS sites, making it significantly easier to manage web server certificates. +The IIS Bound Certificate Store Type, identified by its short name 'IISU,' is designed for the management of certificates bound to IIS (Internet Information Services) servers. This store type allows users to automate and streamline the process of adding, removing, and reenrolling certificates for IIS sites, making it significantly easier to manage web server certificates. ### Key Features and Representation