From fc7f888654f02bb9683ab515f124b821db5d2b53 Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Thu, 13 Oct 2022 16:28:34 -0400 Subject: [PATCH 01/14] changes --- RemoteFile/ICertificateStoreSerializer.cs | 2 +- .../JKS/JKSCertificateStoreSerializer.cs | 2 +- .../ImplementedStoreTypes/KDB/Inventory.cs | 11 + .../KDB/KDBCertificateStoreSerializer.cs | 227 ++++++++++++++++++ .../ImplementedStoreTypes/KDB/Management.cs | 11 + .../PEM/PEMCertificateStoreSerializer.cs | 2 +- .../PKCS12CertificateStoreSerializer.cs | 2 +- RemoteFile/ManagementBase.cs | 2 +- RemoteFile/RemoteCertificateStore.cs | 6 +- .../RemoteHandlers/BaseRemoteHandler.cs | 3 +- RemoteFile/RemoteHandlers/IRemoteHandler.cs | 2 + RemoteFile/RemoteHandlers/SSHHandler.cs | 13 +- RemoteFile/RemoteHandlers/WinRMHandler.cs | 10 +- RemoteFile/manifest.json | 12 + 14 files changed, 290 insertions(+), 15 deletions(-) create mode 100644 RemoteFile/ImplementedStoreTypes/KDB/Inventory.cs create mode 100644 RemoteFile/ImplementedStoreTypes/KDB/KDBCertificateStoreSerializer.cs create mode 100644 RemoteFile/ImplementedStoreTypes/KDB/Management.cs diff --git a/RemoteFile/ICertificateStoreSerializer.cs b/RemoteFile/ICertificateStoreSerializer.cs index c847ad81..f5898ee2 100644 --- a/RemoteFile/ICertificateStoreSerializer.cs +++ b/RemoteFile/ICertificateStoreSerializer.cs @@ -7,7 +7,7 @@ namespace Keyfactor.Extensions.Orchestrator.RemoteFile { interface ICertificateStoreSerializer { - Pkcs12Store DeserializeRemoteCertificateStore(byte[] storeContents, string storePassword, string storeProperties, IRemoteHandler remoteHandler); + Pkcs12Store DeserializeRemoteCertificateStore(byte[] storeContents, string storePath, string storePassword, string storeProperties, IRemoteHandler remoteHandler); List SerializeRemoteCertificateStore(Pkcs12Store certificateStore, string storePath, string storePassword, string storeProperties, IRemoteHandler remoteHandler); } diff --git a/RemoteFile/ImplementedStoreTypes/JKS/JKSCertificateStoreSerializer.cs b/RemoteFile/ImplementedStoreTypes/JKS/JKSCertificateStoreSerializer.cs index 55fba00b..1be4818f 100644 --- a/RemoteFile/ImplementedStoreTypes/JKS/JKSCertificateStoreSerializer.cs +++ b/RemoteFile/ImplementedStoreTypes/JKS/JKSCertificateStoreSerializer.cs @@ -22,7 +22,7 @@ public JKSCertificateStoreSerializer() logger = LogHandler.GetClassLogger(this.GetType()); } - public Pkcs12Store DeserializeRemoteCertificateStore(byte[] storeContents, string storePassword, string storeProperties, IRemoteHandler remoteHandler) + public Pkcs12Store DeserializeRemoteCertificateStore(byte[] storeContents, string storePath, string storePassword, string storeProperties, IRemoteHandler remoteHandler) { logger.MethodEntry(LogLevel.Debug); diff --git a/RemoteFile/ImplementedStoreTypes/KDB/Inventory.cs b/RemoteFile/ImplementedStoreTypes/KDB/Inventory.cs new file mode 100644 index 00000000..3d6811a3 --- /dev/null +++ b/RemoteFile/ImplementedStoreTypes/KDB/Inventory.cs @@ -0,0 +1,11 @@ + +namespace Keyfactor.Extensions.Orchestrator.RemoteFile.KDB +{ + public class Inventory : InventoryBase + { + internal override ICertificateStoreSerializer GetCertificateStoreSerializer() + { + return new KDBCertificateStoreSerializer(); + } + } +} diff --git a/RemoteFile/ImplementedStoreTypes/KDB/KDBCertificateStoreSerializer.cs b/RemoteFile/ImplementedStoreTypes/KDB/KDBCertificateStoreSerializer.cs new file mode 100644 index 00000000..e9a2b1da --- /dev/null +++ b/RemoteFile/ImplementedStoreTypes/KDB/KDBCertificateStoreSerializer.cs @@ -0,0 +1,227 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; + +using Newtonsoft.Json; + +using Keyfactor.Logging; +using Keyfactor.PKI.PrivateKeys; +using Keyfactor.PKI.X509; +using Keyfactor.PKI.PEM; +using Keyfactor.Extensions.Orchestrator.RemoteFile.RemoteHandlers; +using Keyfactor.Extensions.Orchestrator.RemoteFile.Models; + +using Microsoft.Extensions.Logging; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Pkcs; +using Org.BouncyCastle.X509; + +namespace Keyfactor.Extensions.Orchestrator.RemoteFile.KDB +{ + class KDBCertificateStoreSerializer : ICertificateStoreSerializer + { + private ILogger logger; + + public KDBCertificateStoreSerializer() + { + logger = LogHandler.GetClassLogger(this.GetType()); + } + + public Pkcs12Store DeserializeRemoteCertificateStore(byte[] storeContentBytes, string storePath, string storePassword, string storeProperties, IRemoteHandler remoteHandler) + { + logger.MethodEntry(LogLevel.Debug); + + Pkcs12StoreBuilder storeBuilder = new Pkcs12StoreBuilder(); + Pkcs12Store store = storeBuilder.Build(); + + string tempStoreFile = Guid.NewGuid().ToString().Replace("-", string.Empty) + ".kdb"; + string tempCertFile = Guid.NewGuid().ToString().Replace("-", string.Empty) + ".pem"; + + remoteHandler.UploadCertificateFile(storePath, tempStoreFile, storeContentBytes); + + string command = $"bash gskcapicmd -cert -list -db '{storePath}{tempStoreFile}' -pw '{storePassword}'"; + + try + { + string aliases = remoteHandler.RunCommand(command, null, ApplicationSettings.UseSudo, null); + List aliasList = new List(aliases.Replace($"\n", string.Empty).Replace($"\t", string.Empty).Replace($"\"", string.Empty).Split(new char[] { '!' })); + } + catch (Exception ex) + { + throw ex; + } + finally + { + remoteHandler.RemoveCertificateFile(storePath, tempStoreFile); + remoteHandler.RemoveCertificateFile(storePath, tempCertFile); + } + + + //string storeContents = Encoding.ASCII.GetString(storeContentBytes); + //X509CertificateEntry[] certificates = GetCertificates(storeContents); + + //if (IsTrustStore) + //{ + // foreach(X509CertificateEntry certificate in certificates) + // { + // store.SetCertificateEntry(CertificateConverterFactory.FromBouncyCastleCertificate(certificate.Certificate).ToX509Certificate2().Thumbprint, certificate); + // } + //} + //else + //{ + // AsymmetricKeyEntry keyEntry = GetPrivateKey(storeContents, storePassword ?? string.Empty, remoteHandler); + // store.SetKeyEntry(CertificateConverterFactory.FromBouncyCastleCertificate(certificates[0].Certificate).ToX509Certificate2().Thumbprint, keyEntry, certificates); + //} + + //// Second Pkcs12Store necessary because of an obscure BC bug where creating a Pkcs12Store without .Load (code above using "Set" methods only) does not set all internal hashtables necessary to avoid an error later + //// when processing store. + //MemoryStream ms = new MemoryStream(); + //store.Save(ms, string.IsNullOrEmpty(storePassword) ? new char[0] : storePassword.ToCharArray(), new Org.BouncyCastle.Security.SecureRandom()); + //ms.Position = 0; + + //Pkcs12Store newStore = storeBuilder.Build(); + //newStore.Load(ms, string.IsNullOrEmpty(storePassword) ? new char[0] : storePassword.ToCharArray()); + + logger.MethodExit(LogLevel.Debug); + return store; + } + + public List SerializeRemoteCertificateStore(Pkcs12Store certificateStore, string storePath, string storePassword, string storeProperties, IRemoteHandler remoteHandler) + { + logger.MethodEntry(LogLevel.Debug); + + //LoadCustomProperties(storeProperties); + + string pemString = string.Empty; + string keyString = string.Empty; + List storeInfo = new List(); + + //if (IsTrustStore) + //{ + // foreach (string alias in certificateStore.Aliases) + // { + // if (certificateStore.IsKeyEntry(alias)) + // throw new RemoteFileException("Cannot add a certificate with a private key to a PEM trust store."); + + // CertificateConverter certConverter = CertificateConverterFactory.FromBouncyCastleCertificate(certificateStore.GetCertificate(alias).Certificate); + // pemString += certConverter.ToPEM(true); + // } + //} + //else + //{ + // bool keyEntryProcessed = false; + // foreach (string alias in certificateStore.Aliases) + // { + // if (keyEntryProcessed) + // throw new RemoteFileException("Cannot add a new certificate to a PEM store that already contains a certificate/key entry."); + // else + // keyEntryProcessed = true; + + // if (!certificateStore.IsKeyEntry(alias)) + // throw new RemoteFileException("No private key found. Private key must be present to add entry to a non-Trust PEM certificate store."); + + // AsymmetricKeyParameter privateKey = certificateStore.GetKey(alias).Key; + // X509CertificateEntry[] certEntries = certificateStore.GetCertificateChain(alias); + // AsymmetricKeyParameter publicKey = certEntries[0].Certificate.GetPublicKey(); + // PrivateKeyConverter keyConverter = PrivateKeyConverterFactory.FromBCKeyPair(privateKey, publicKey, false); + + // byte[] privateKeyBytes = string.IsNullOrEmpty(storePassword) ? keyConverter.ToPkcs8BlobUnencrypted() : keyConverter.ToPkcs8Blob(storePassword); + // keyString = PemUtilities.DERToPEM(privateKeyBytes, string.IsNullOrEmpty(storePassword) ? PemUtilities.PemObjectType.PrivateKey : PemUtilities.PemObjectType.EncryptedPrivateKey); + + // X509CertificateEntry[] chainEntries = certificateStore.GetCertificateChain(alias); + // CertificateConverter certConverter = CertificateConverterFactory.FromBouncyCastleCertificate(chainEntries[0].Certificate); + + // pemString = certConverter.ToPEM(true); + // if (string.IsNullOrEmpty(SeparatePrivateKeyFilePath)) + // pemString += keyString; + + // if (IncludesChain) + // { + // for (int i = 1; i < chainEntries.Length; i++) + // { + // CertificateConverter chainConverter = CertificateConverterFactory.FromBouncyCastleCertificate(chainEntries[i].Certificate); + // pemString += chainConverter.ToPEM(true); + // } + // } + // } + //} + + //storeInfo.Add(new SerializedStoreInfo() { FilePath = storePath, Contents = Encoding.ASCII.GetBytes(pemString) }); + //if (!string.IsNullOrEmpty(SeparatePrivateKeyFilePath)) + // storeInfo.Add(new SerializedStoreInfo() { FilePath = SeparatePrivateKeyFilePath, Contents = Encoding.ASCII.GetBytes(keyString) }); + + //logger.MethodExit(LogLevel.Debug); + + return storeInfo; + } + + //private X509CertificateEntry[] GetCertificates(string certificates) + //{ + // logger.MethodEntry(LogLevel.Debug); + + // List certificateEntries = new List(); + + // try + // { + // while (certificates.Contains(CertDelimBeg)) + // { + // int certStart = certificates.IndexOf(CertDelimBeg); + // int certLength = certificates.IndexOf(CertDelimEnd) + CertDelimEnd.Length - certStart; + // string certificate = certificates.Substring(certStart, certLength); + + // CertificateConverter c2 = CertificateConverterFactory.FromPEM(Encoding.ASCII.GetBytes(certificate.Replace(CertDelimBeg, string.Empty).Replace(CertDelimEnd, string.Empty))); + // X509Certificate bcCert = c2.ToBouncyCastleCertificate(); + // certificateEntries.Add(new X509CertificateEntry(bcCert)); + + // certificates = certificates.Substring(certStart + certLength - 1); + // } + // } + // catch (Exception ex) + // { + // throw new RemoteFileException($"Error attempting to retrieve certificate chain.", ex); + // } + + // logger.MethodExit(LogLevel.Debug); + + // return certificateEntries.ToArray(); + //} + + //private AsymmetricKeyEntry GetPrivateKey(string storeContents, string storePassword, IRemoteHandler remoteHandler) + //{ + // logger.MethodEntry(LogLevel.Debug); + + // if (!String.IsNullOrEmpty(SeparatePrivateKeyFilePath)) + // { + // storeContents = Encoding.ASCII.GetString(remoteHandler.DownloadCertificateFile(SeparatePrivateKeyFilePath)); + // } + + // string privateKey = string.Empty; + // foreach (string begDelim in PrivateKeyDelimeters) + // { + // string endDelim = begDelim.Replace("BEGIN", "END"); + + // int keyStart = storeContents.IndexOf(begDelim); + // if (keyStart == -1) + // continue; + // int keyLength = storeContents.IndexOf(endDelim) + endDelim.Length - keyStart; + // if (keyLength == -1) + // throw new RemoteFileException("Invalid private key: No ending private key delimiter found."); + + // privateKey = storeContents.Substring(keyStart, keyLength).Replace(begDelim, string.Empty).Replace(endDelim, string.Empty); + + // break; + // } + + // if (string.IsNullOrEmpty(privateKey)) + // throw new RemoteFileException("Invalid private key: No private key found."); + + // PrivateKeyConverter c = PrivateKeyConverterFactory.FromPkcs8Blob(Convert.FromBase64String(privateKey), storePassword); + + // logger.MethodExit(LogLevel.Debug); + + // return new AsymmetricKeyEntry(c.ToBCPrivateKey()); + //} + } +} diff --git a/RemoteFile/ImplementedStoreTypes/KDB/Management.cs b/RemoteFile/ImplementedStoreTypes/KDB/Management.cs new file mode 100644 index 00000000..c56b07fd --- /dev/null +++ b/RemoteFile/ImplementedStoreTypes/KDB/Management.cs @@ -0,0 +1,11 @@ + +namespace Keyfactor.Extensions.Orchestrator.RemoteFile.KDB +{ + public class Management : ManagementBase + { + internal override ICertificateStoreSerializer GetCertificateStoreSerializer() + { + return new KDBCertificateStoreSerializer(); + } + } +} diff --git a/RemoteFile/ImplementedStoreTypes/PEM/PEMCertificateStoreSerializer.cs b/RemoteFile/ImplementedStoreTypes/PEM/PEMCertificateStoreSerializer.cs index 81b998b5..8155d10f 100644 --- a/RemoteFile/ImplementedStoreTypes/PEM/PEMCertificateStoreSerializer.cs +++ b/RemoteFile/ImplementedStoreTypes/PEM/PEMCertificateStoreSerializer.cs @@ -37,7 +37,7 @@ public PEMCertificateStoreSerializer() logger = LogHandler.GetClassLogger(this.GetType()); } - public Pkcs12Store DeserializeRemoteCertificateStore(byte[] storeContentBytes, string storePassword, string storeProperties, IRemoteHandler remoteHandler) + public Pkcs12Store DeserializeRemoteCertificateStore(byte[] storeContentBytes, string storePath, string storePassword, string storeProperties, IRemoteHandler remoteHandler) { logger.MethodEntry(LogLevel.Debug); diff --git a/RemoteFile/ImplementedStoreTypes/PKCS12/PKCS12CertificateStoreSerializer.cs b/RemoteFile/ImplementedStoreTypes/PKCS12/PKCS12CertificateStoreSerializer.cs index 44402508..373485f0 100644 --- a/RemoteFile/ImplementedStoreTypes/PKCS12/PKCS12CertificateStoreSerializer.cs +++ b/RemoteFile/ImplementedStoreTypes/PKCS12/PKCS12CertificateStoreSerializer.cs @@ -9,7 +9,7 @@ namespace Keyfactor.Extensions.Orchestrator.RemoteFile.PKCS12 { class PKCS12CertificateStoreSerializer : ICertificateStoreSerializer { - public Pkcs12Store DeserializeRemoteCertificateStore(byte[] storeContents, string storePassword, string storeProperties, IRemoteHandler remoteHandler) + public Pkcs12Store DeserializeRemoteCertificateStore(byte[] storeContents, string storePath, string storePassword, string storeProperties, IRemoteHandler remoteHandler) { Pkcs12StoreBuilder storeBuilder = new Pkcs12StoreBuilder(); Pkcs12Store store = storeBuilder.Build(); diff --git a/RemoteFile/ManagementBase.cs b/RemoteFile/ManagementBase.cs index 15dbb341..9d8a922a 100644 --- a/RemoteFile/ManagementBase.cs +++ b/RemoteFile/ManagementBase.cs @@ -126,4 +126,4 @@ private void CreateStore(ManagementJobConfiguration config) certificateStore.CreateCertificateStore(config.CertificateStoreDetails.StorePath, linuxFilePermissions); } } -} +} \ No newline at end of file diff --git a/RemoteFile/RemoteCertificateStore.cs b/RemoteFile/RemoteCertificateStore.cs index c84543fe..e20f46ec 100644 --- a/RemoteFile/RemoteCertificateStore.cs +++ b/RemoteFile/RemoteCertificateStore.cs @@ -109,7 +109,7 @@ internal void LoadCertificateStore(ICertificateStoreSerializer certificateStoreS if (byteContents.Length < 5) return; - CertificateStore = certificateStoreSerializer.DeserializeRemoteCertificateStore(byteContents, StorePassword, storeProperties, RemoteHandler); + CertificateStore = certificateStoreSerializer.DeserializeRemoteCertificateStore(byteContents, StorePath, StorePassword, storeProperties, RemoteHandler); logger.MethodExit(LogLevel.Debug); } @@ -424,8 +424,8 @@ private PathFile SplitStorePathFile(string pathFileName) try { - string workingPathFileName = pathFileName.Replace(@"\", @"/"); - int separatorIndex = workingPathFileName.LastIndexOf(@"/"); + string storePathFileName = pathFileName.Replace(@"\", @"/"); + int separatorIndex = storePathFileName.LastIndexOf(@"/"); logger.MethodExit(LogLevel.Debug); return new PathFile() { Path = pathFileName.Substring(0, separatorIndex + 1), File = pathFileName.Substring(separatorIndex + 1) }; diff --git a/RemoteFile/RemoteHandlers/BaseRemoteHandler.cs b/RemoteFile/RemoteHandlers/BaseRemoteHandler.cs index e343aa0d..7deb41bd 100644 --- a/RemoteFile/RemoteHandlers/BaseRemoteHandler.cs +++ b/RemoteFile/RemoteHandlers/BaseRemoteHandler.cs @@ -14,7 +14,6 @@ namespace Keyfactor.Extensions.Orchestrator.RemoteFile.RemoteHandlers abstract class BaseRemoteHandler : IRemoteHandler { internal ILogger _logger; - internal const string KEYTOOL_ERROR = "password was incorrect"; internal const string PASSWORD_MASK_VALUE = "[PASSWORD]"; internal const int PASSWORD_LENGTH_MAX = 100; @@ -38,5 +37,7 @@ public BaseRemoteHandler() public abstract void CreateEmptyStoreFile(string path, string linuxFilePermissions); public abstract bool DoesFileExist(string path); + + public abstract void RemoveCertificateFile(string path, string fileName); } } diff --git a/RemoteFile/RemoteHandlers/IRemoteHandler.cs b/RemoteFile/RemoteHandlers/IRemoteHandler.cs index fa9c797d..b86c9d65 100644 --- a/RemoteFile/RemoteHandlers/IRemoteHandler.cs +++ b/RemoteFile/RemoteHandlers/IRemoteHandler.cs @@ -26,5 +26,7 @@ interface IRemoteHandler void CreateEmptyStoreFile(string path, string linuxFilePermissions); bool DoesFileExist(string path); + + void RemoveCertificateFile(string path, string fileName); } } diff --git a/RemoteFile/RemoteHandlers/SSHHandler.cs b/RemoteFile/RemoteHandlers/SSHHandler.cs index e6ca3ced..a6b77b00 100644 --- a/RemoteFile/RemoteHandlers/SSHHandler.cs +++ b/RemoteFile/RemoteHandlers/SSHHandler.cs @@ -112,8 +112,8 @@ public override string RunCommand(string commandText, object[] arguments, bool w command.Execute(); _logger.LogDebug($"SSH Results: {displayCommand}::: {command.Result}::: {command.Error}"); - if (command.Result.ToLower().Contains(KEYTOOL_ERROR)) - throw new ApplicationException(command.Result); + if (!String.IsNullOrEmpty(command.Error)) + throw new ApplicationException(command.Error); _logger.MethodExit(LogLevel.Debug); @@ -224,7 +224,7 @@ public override byte[] DownloadCertificateFile(string path) SplitStorePathFile(path, out altPathOnly, out altFileNameOnly); downloadPath = ApplicationSettings.SeparateUploadFilePath + altFileNameOnly; RunCommand($"cp {path} {downloadPath}", null, ApplicationSettings.UseSudo, null); - RunCommand($"sudo chown {Connection.Username} {path}", null, ApplicationSettings.UseSudo, null); + RunCommand($"sudo chown {Connection.Username} {downloadPath}", null, ApplicationSettings.UseSudo, null); } bool scpError = false; @@ -340,6 +340,13 @@ public static void AreLinuxPermissionsValid(string permissions) throw new RemoteFileException($"Invalid format for Linux file permissions. This value must be exactly 3 digits long with each digit between 0-7 but found {permissions} instead."); } + public override void RemoveCertificateFile(string path, string fileName) + { + _logger.LogDebug($"RemoveCertificateFile: {path} {fileName}"); + + RunCommand($"rm {path}{fileName}", null, ApplicationSettings.UseSudo, null); + } + private void SplitStorePathFile(string pathFileName, out string path, out string fileName) { _logger.MethodEntry(LogLevel.Debug); diff --git a/RemoteFile/RemoteHandlers/WinRMHandler.cs b/RemoteFile/RemoteHandlers/WinRMHandler.cs index 3a9a6eb0..dbd3b217 100644 --- a/RemoteFile/RemoteHandlers/WinRMHandler.cs +++ b/RemoteFile/RemoteHandlers/WinRMHandler.cs @@ -132,9 +132,6 @@ public override string RunCommand(string commandText, object[] parameters, bool else _logger.LogDebug($"WinRM Results: {displayCommand}::: {result}"); - if (result.ToLower().Contains(KEYTOOL_ERROR)) - throw new ApplicationException(result); - _logger.MethodExit(LogLevel.Debug); return result; @@ -240,6 +237,13 @@ public override bool DoesFileExist(string path) return Convert.ToBoolean(RunCommand($@"Test-Path -path ""{path}""", null, false, null)); } + public override void RemoveCertificateFile(string path, string fileName) + { + _logger.LogDebug($"RemoveCertificateFile: {path} {fileName}"); + + RunCommand($"rm {path}{fileName}", null, false, null); + } + private string FormatResult(ICollection results) { diff --git a/RemoteFile/manifest.json b/RemoteFile/manifest.json index 759fe13f..a79fe9ad 100644 --- a/RemoteFile/manifest.json +++ b/RemoteFile/manifest.json @@ -36,6 +36,18 @@ "CertStores.RFJKS.Discovery": { "assemblypath": "RemoteFile.dll", "TypeFullName": "Keyfactor.Extensions.Orchestrator.RemoteFile.Discovery" + }, + "CertStores.RFKDB.Inventory": { + "assemblypath": "RemoteFile.dll", + "TypeFullName": "Keyfactor.Extensions.Orchestrator.RemoteFile.KDB.Inventory" + }, + "CertStores.RFKDB.Management": { + "assemblypath": "RemoteFile.dll", + "TypeFullName": "Keyfactor.Extensions.Orchestrator.RemoteFile.KDB.Management" + }, + "CertStores.RFKDB.Discovery": { + "assemblypath": "RemoteFile.dll", + "TypeFullName": "Keyfactor.Extensions.Orchestrator.RemoteFile.Discovery" } } } From 788f3da673a647db2e0d93dca10470287bf00137 Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Tue, 18 Oct 2022 15:31:45 -0400 Subject: [PATCH 02/14] changes --- RemoteFile/ICertificateStoreSerializer.cs | 2 +- .../JKS/JKSCertificateStoreSerializer.cs | 4 +- .../KDB/KDBCertificateStoreSerializer.cs | 210 ++++-------------- .../PEM/PEMCertificateStoreSerializer.cs | 4 +- .../PKCS12CertificateStoreSerializer.cs | 4 +- RemoteFile/ManagementBase.cs | 6 +- RemoteFile/RemoteCertificateStore.cs | 33 ++- 7 files changed, 66 insertions(+), 197 deletions(-) diff --git a/RemoteFile/ICertificateStoreSerializer.cs b/RemoteFile/ICertificateStoreSerializer.cs index f5898ee2..a1a1b30f 100644 --- a/RemoteFile/ICertificateStoreSerializer.cs +++ b/RemoteFile/ICertificateStoreSerializer.cs @@ -9,6 +9,6 @@ interface ICertificateStoreSerializer { Pkcs12Store DeserializeRemoteCertificateStore(byte[] storeContents, string storePath, string storePassword, string storeProperties, IRemoteHandler remoteHandler); - List SerializeRemoteCertificateStore(Pkcs12Store certificateStore, string storePath, string storePassword, string storeProperties, IRemoteHandler remoteHandler); + List SerializeRemoteCertificateStore(Pkcs12Store certificateStore, string storePath, string storeFileName, string storePassword, string storeProperties, IRemoteHandler remoteHandler); } } diff --git a/RemoteFile/ImplementedStoreTypes/JKS/JKSCertificateStoreSerializer.cs b/RemoteFile/ImplementedStoreTypes/JKS/JKSCertificateStoreSerializer.cs index 1be4818f..79e02a88 100644 --- a/RemoteFile/ImplementedStoreTypes/JKS/JKSCertificateStoreSerializer.cs +++ b/RemoteFile/ImplementedStoreTypes/JKS/JKSCertificateStoreSerializer.cs @@ -71,7 +71,7 @@ public Pkcs12Store DeserializeRemoteCertificateStore(byte[] storeContents, strin return pkcs12StoreNew; } - public List SerializeRemoteCertificateStore(Pkcs12Store certificateStore, string storePath, string storePassword, string storeProperties, IRemoteHandler remoteHandler) + public List SerializeRemoteCertificateStore(Pkcs12Store certificateStore, string storePath, string storeFileName, string storePassword, string storeProperties, IRemoteHandler remoteHandler) { logger.MethodEntry(LogLevel.Debug); @@ -103,7 +103,7 @@ public List SerializeRemoteCertificateStore(Pkcs12Store cer jksStore.Save(outStream, string.IsNullOrEmpty(storePassword) ? new char[0] : storePassword.ToCharArray()); List storeInfo = new List(); - storeInfo.Add(new SerializedStoreInfo() { FilePath = storePath, Contents = outStream.ToArray() }); + storeInfo.Add(new SerializedStoreInfo() { FilePath = storePath+storeFileName, Contents = outStream.ToArray() }); logger.MethodExit(LogLevel.Debug); return storeInfo; diff --git a/RemoteFile/ImplementedStoreTypes/KDB/KDBCertificateStoreSerializer.cs b/RemoteFile/ImplementedStoreTypes/KDB/KDBCertificateStoreSerializer.cs index e9a2b1da..a44504f8 100644 --- a/RemoteFile/ImplementedStoreTypes/KDB/KDBCertificateStoreSerializer.cs +++ b/RemoteFile/ImplementedStoreTypes/KDB/KDBCertificateStoreSerializer.cs @@ -1,22 +1,14 @@ using System; using System.Collections.Generic; -using System.Text; using System.IO; -using Newtonsoft.Json; - using Keyfactor.Logging; -using Keyfactor.PKI.PrivateKeys; -using Keyfactor.PKI.X509; -using Keyfactor.PKI.PEM; using Keyfactor.Extensions.Orchestrator.RemoteFile.RemoteHandlers; using Keyfactor.Extensions.Orchestrator.RemoteFile.Models; using Microsoft.Extensions.Logging; -using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Pkcs; -using Org.BouncyCastle.X509; namespace Keyfactor.Extensions.Orchestrator.RemoteFile.KDB { @@ -33,20 +25,24 @@ public Pkcs12Store DeserializeRemoteCertificateStore(byte[] storeContentBytes, s { logger.MethodEntry(LogLevel.Debug); + string kdbCommand = storePath.Substring(0, 1) == "/" ? "gskcapicmd" : "gsk8capicmd"; + Pkcs12StoreBuilder storeBuilder = new Pkcs12StoreBuilder(); Pkcs12Store store = storeBuilder.Build(); string tempStoreFile = Guid.NewGuid().ToString().Replace("-", string.Empty) + ".kdb"; - string tempCertFile = Guid.NewGuid().ToString().Replace("-", string.Empty) + ".pem"; + string tempCertFile = Guid.NewGuid().ToString().Replace("-", string.Empty) + ".p12"; remoteHandler.UploadCertificateFile(storePath, tempStoreFile, storeContentBytes); - - string command = $"bash gskcapicmd -cert -list -db '{storePath}{tempStoreFile}' -pw '{storePassword}'"; + + string command = $"bash {kdbCommand} -keydb -convert -db '{storePath}{tempStoreFile}' -pw '{storePassword}' -type kdb -new_db '{storePath}{tempCertFile}' -new_pw '{storePassword}' -new_format p12"; try { - string aliases = remoteHandler.RunCommand(command, null, ApplicationSettings.UseSudo, null); - List aliasList = new List(aliases.Replace($"\n", string.Empty).Replace($"\t", string.Empty).Replace($"\"", string.Empty).Split(new char[] { '!' })); + remoteHandler.RunCommand(command, null, ApplicationSettings.UseSudo, null); + + byte[] storeBytes = remoteHandler.DownloadCertificateFile($"{storePath}{tempCertFile}"); + store.Load(new MemoryStream(storeBytes), string.IsNullOrEmpty(storePassword) ? new char[0] : storePassword.ToCharArray()); } catch (Exception ex) { @@ -54,174 +50,48 @@ public Pkcs12Store DeserializeRemoteCertificateStore(byte[] storeContentBytes, s } finally { - remoteHandler.RemoveCertificateFile(storePath, tempStoreFile); - remoteHandler.RemoveCertificateFile(storePath, tempCertFile); + try { remoteHandler.RemoveCertificateFile(storePath, tempStoreFile); } catch (Exception) { }; + try { remoteHandler.RemoveCertificateFile(storePath, tempCertFile); } catch (Exception) { }; } - - //string storeContents = Encoding.ASCII.GetString(storeContentBytes); - //X509CertificateEntry[] certificates = GetCertificates(storeContents); - - //if (IsTrustStore) - //{ - // foreach(X509CertificateEntry certificate in certificates) - // { - // store.SetCertificateEntry(CertificateConverterFactory.FromBouncyCastleCertificate(certificate.Certificate).ToX509Certificate2().Thumbprint, certificate); - // } - //} - //else - //{ - // AsymmetricKeyEntry keyEntry = GetPrivateKey(storeContents, storePassword ?? string.Empty, remoteHandler); - // store.SetKeyEntry(CertificateConverterFactory.FromBouncyCastleCertificate(certificates[0].Certificate).ToX509Certificate2().Thumbprint, keyEntry, certificates); - //} - - //// Second Pkcs12Store necessary because of an obscure BC bug where creating a Pkcs12Store without .Load (code above using "Set" methods only) does not set all internal hashtables necessary to avoid an error later - //// when processing store. - //MemoryStream ms = new MemoryStream(); - //store.Save(ms, string.IsNullOrEmpty(storePassword) ? new char[0] : storePassword.ToCharArray(), new Org.BouncyCastle.Security.SecureRandom()); - //ms.Position = 0; - - //Pkcs12Store newStore = storeBuilder.Build(); - //newStore.Load(ms, string.IsNullOrEmpty(storePassword) ? new char[0] : storePassword.ToCharArray()); - logger.MethodExit(LogLevel.Debug); return store; } - public List SerializeRemoteCertificateStore(Pkcs12Store certificateStore, string storePath, string storePassword, string storeProperties, IRemoteHandler remoteHandler) + public List SerializeRemoteCertificateStore(Pkcs12Store certificateStore, string storePath, string storeFileName, string storePassword, string storeProperties, IRemoteHandler remoteHandler) { logger.MethodEntry(LogLevel.Debug); - //LoadCustomProperties(storeProperties); - - string pemString = string.Empty; - string keyString = string.Empty; List storeInfo = new List(); + string kdbCommand = storePath.Substring(0, 1) == "/" ? "gskcapicmd" : "gsk8capicmd"; - //if (IsTrustStore) - //{ - // foreach (string alias in certificateStore.Aliases) - // { - // if (certificateStore.IsKeyEntry(alias)) - // throw new RemoteFileException("Cannot add a certificate with a private key to a PEM trust store."); - - // CertificateConverter certConverter = CertificateConverterFactory.FromBouncyCastleCertificate(certificateStore.GetCertificate(alias).Certificate); - // pemString += certConverter.ToPEM(true); - // } - //} - //else - //{ - // bool keyEntryProcessed = false; - // foreach (string alias in certificateStore.Aliases) - // { - // if (keyEntryProcessed) - // throw new RemoteFileException("Cannot add a new certificate to a PEM store that already contains a certificate/key entry."); - // else - // keyEntryProcessed = true; - - // if (!certificateStore.IsKeyEntry(alias)) - // throw new RemoteFileException("No private key found. Private key must be present to add entry to a non-Trust PEM certificate store."); - - // AsymmetricKeyParameter privateKey = certificateStore.GetKey(alias).Key; - // X509CertificateEntry[] certEntries = certificateStore.GetCertificateChain(alias); - // AsymmetricKeyParameter publicKey = certEntries[0].Certificate.GetPublicKey(); - // PrivateKeyConverter keyConverter = PrivateKeyConverterFactory.FromBCKeyPair(privateKey, publicKey, false); - - // byte[] privateKeyBytes = string.IsNullOrEmpty(storePassword) ? keyConverter.ToPkcs8BlobUnencrypted() : keyConverter.ToPkcs8Blob(storePassword); - // keyString = PemUtilities.DERToPEM(privateKeyBytes, string.IsNullOrEmpty(storePassword) ? PemUtilities.PemObjectType.PrivateKey : PemUtilities.PemObjectType.EncryptedPrivateKey); - - // X509CertificateEntry[] chainEntries = certificateStore.GetCertificateChain(alias); - // CertificateConverter certConverter = CertificateConverterFactory.FromBouncyCastleCertificate(chainEntries[0].Certificate); - - // pemString = certConverter.ToPEM(true); - // if (string.IsNullOrEmpty(SeparatePrivateKeyFilePath)) - // pemString += keyString; - - // if (IncludesChain) - // { - // for (int i = 1; i < chainEntries.Length; i++) - // { - // CertificateConverter chainConverter = CertificateConverterFactory.FromBouncyCastleCertificate(chainEntries[i].Certificate); - // pemString += chainConverter.ToPEM(true); - // } - // } - // } - //} - - //storeInfo.Add(new SerializedStoreInfo() { FilePath = storePath, Contents = Encoding.ASCII.GetBytes(pemString) }); - //if (!string.IsNullOrEmpty(SeparatePrivateKeyFilePath)) - // storeInfo.Add(new SerializedStoreInfo() { FilePath = SeparatePrivateKeyFilePath, Contents = Encoding.ASCII.GetBytes(keyString) }); - - //logger.MethodExit(LogLevel.Debug); - - return storeInfo; - } - - //private X509CertificateEntry[] GetCertificates(string certificates) - //{ - // logger.MethodEntry(LogLevel.Debug); - - // List certificateEntries = new List(); - - // try - // { - // while (certificates.Contains(CertDelimBeg)) - // { - // int certStart = certificates.IndexOf(CertDelimBeg); - // int certLength = certificates.IndexOf(CertDelimEnd) + CertDelimEnd.Length - certStart; - // string certificate = certificates.Substring(certStart, certLength); - - // CertificateConverter c2 = CertificateConverterFactory.FromPEM(Encoding.ASCII.GetBytes(certificate.Replace(CertDelimBeg, string.Empty).Replace(CertDelimEnd, string.Empty))); - // X509Certificate bcCert = c2.ToBouncyCastleCertificate(); - // certificateEntries.Add(new X509CertificateEntry(bcCert)); - - // certificates = certificates.Substring(certStart + certLength - 1); - // } - // } - // catch (Exception ex) - // { - // throw new RemoteFileException($"Error attempting to retrieve certificate chain.", ex); - // } - - // logger.MethodExit(LogLevel.Debug); - - // return certificateEntries.ToArray(); - //} - - //private AsymmetricKeyEntry GetPrivateKey(string storeContents, string storePassword, IRemoteHandler remoteHandler) - //{ - // logger.MethodEntry(LogLevel.Debug); - - // if (!String.IsNullOrEmpty(SeparatePrivateKeyFilePath)) - // { - // storeContents = Encoding.ASCII.GetString(remoteHandler.DownloadCertificateFile(SeparatePrivateKeyFilePath)); - // } - - // string privateKey = string.Empty; - // foreach (string begDelim in PrivateKeyDelimeters) - // { - // string endDelim = begDelim.Replace("BEGIN", "END"); - - // int keyStart = storeContents.IndexOf(begDelim); - // if (keyStart == -1) - // continue; - // int keyLength = storeContents.IndexOf(endDelim) + endDelim.Length - keyStart; - // if (keyLength == -1) - // throw new RemoteFileException("Invalid private key: No ending private key delimiter found."); - - // privateKey = storeContents.Substring(keyStart, keyLength).Replace(begDelim, string.Empty).Replace(endDelim, string.Empty); - - // break; - // } - - // if (string.IsNullOrEmpty(privateKey)) - // throw new RemoteFileException("Invalid private key: No private key found."); - - // PrivateKeyConverter c = PrivateKeyConverterFactory.FromPkcs8Blob(Convert.FromBase64String(privateKey), storePassword); - - // logger.MethodExit(LogLevel.Debug); + string tempStoreFile = Guid.NewGuid().ToString().Replace("-", string.Empty) + ".kdb"; + string tempCertFile = Guid.NewGuid().ToString().Replace("-", string.Empty) + ".p12"; - // return new AsymmetricKeyEntry(c.ToBCPrivateKey()); - //} + string command = $"bash {kdbCommand} -keydb -convert -db '{storePath}{tempCertFile}' -pw '{storePassword}' -type p12 -new_db '{storePath}{tempStoreFile}' -new_pw '{storePassword}' -new_format kdb"; + + try + { + using (MemoryStream ms = new MemoryStream()) + { + certificateStore.Save(ms, string.IsNullOrEmpty(storePassword) ? new char[0] : storePassword.ToCharArray(), new Org.BouncyCastle.Security.SecureRandom()); + remoteHandler.UploadCertificateFile(storePath, tempCertFile, ms.ToArray()); + } + remoteHandler.RunCommand(command, null, ApplicationSettings.UseSudo, null); + byte[] storeContents = remoteHandler.DownloadCertificateFile($"{storePath}{tempStoreFile}"); + + storeInfo.Add(new SerializedStoreInfo() { Contents = storeContents, FilePath = storePath+storeFileName }); + return storeInfo; + } + catch (Exception ex) + { + throw ex; + } + finally + { + try { remoteHandler.RemoveCertificateFile(storePath, tempStoreFile); } catch (Exception) { }; + try { remoteHandler.RemoveCertificateFile(storePath, tempCertFile); } catch (Exception) { }; + } + } } } diff --git a/RemoteFile/ImplementedStoreTypes/PEM/PEMCertificateStoreSerializer.cs b/RemoteFile/ImplementedStoreTypes/PEM/PEMCertificateStoreSerializer.cs index 8155d10f..4e94e21a 100644 --- a/RemoteFile/ImplementedStoreTypes/PEM/PEMCertificateStoreSerializer.cs +++ b/RemoteFile/ImplementedStoreTypes/PEM/PEMCertificateStoreSerializer.cs @@ -75,7 +75,7 @@ public Pkcs12Store DeserializeRemoteCertificateStore(byte[] storeContentBytes, s return newStore; } - public List SerializeRemoteCertificateStore(Pkcs12Store certificateStore, string storePath, string storePassword, string storeProperties, IRemoteHandler remoteHandler) + public List SerializeRemoteCertificateStore(Pkcs12Store certificateStore, string storePath, string storeFileName, string storePassword, string storeProperties, IRemoteHandler remoteHandler) { logger.MethodEntry(LogLevel.Debug); @@ -135,7 +135,7 @@ public List SerializeRemoteCertificateStore(Pkcs12Store cer } } - storeInfo.Add(new SerializedStoreInfo() { FilePath = storePath, Contents = Encoding.ASCII.GetBytes(pemString) }); + storeInfo.Add(new SerializedStoreInfo() { FilePath = storePath+storeFileName, Contents = Encoding.ASCII.GetBytes(pemString) }); if (!string.IsNullOrEmpty(SeparatePrivateKeyFilePath)) storeInfo.Add(new SerializedStoreInfo() { FilePath = SeparatePrivateKeyFilePath, Contents = Encoding.ASCII.GetBytes(keyString) }); diff --git a/RemoteFile/ImplementedStoreTypes/PKCS12/PKCS12CertificateStoreSerializer.cs b/RemoteFile/ImplementedStoreTypes/PKCS12/PKCS12CertificateStoreSerializer.cs index 373485f0..69157f1e 100644 --- a/RemoteFile/ImplementedStoreTypes/PKCS12/PKCS12CertificateStoreSerializer.cs +++ b/RemoteFile/ImplementedStoreTypes/PKCS12/PKCS12CertificateStoreSerializer.cs @@ -22,14 +22,14 @@ public Pkcs12Store DeserializeRemoteCertificateStore(byte[] storeContents, strin return store; } - public List SerializeRemoteCertificateStore(Pkcs12Store certificateStore, string storePath, string storePassword, string storeProperties, IRemoteHandler remoteHandler) + public List SerializeRemoteCertificateStore(Pkcs12Store certificateStore, string storePath, string storeFileName, string storePassword, string storeProperties, IRemoteHandler remoteHandler) { using (MemoryStream outStream = new MemoryStream()) { certificateStore.Save(outStream, string.IsNullOrEmpty(storePassword) ? new char[0] : storePassword.ToCharArray(), new Org.BouncyCastle.Security.SecureRandom()); List storeInfo = new List(); - storeInfo.Add(new SerializedStoreInfo() { FilePath = storePath, Contents = outStream.ToArray() }); + storeInfo.Add(new SerializedStoreInfo() { FilePath = storePath+storeFileName, Contents = outStream.ToArray() }); return storeInfo; } diff --git a/RemoteFile/ManagementBase.cs b/RemoteFile/ManagementBase.cs index 9d8a922a..73991502 100644 --- a/RemoteFile/ManagementBase.cs +++ b/RemoteFile/ManagementBase.cs @@ -49,6 +49,8 @@ public JobResult ProcessJob(ManagementJobConfiguration config) ApplicationSettings.Initialize(this.GetType().Assembly.Location); certificateStore = new RemoteCertificateStore(config.CertificateStoreDetails.ClientMachine, config.ServerUsername, config.ServerPassword, config.CertificateStoreDetails.StorePath, config.CertificateStoreDetails.StorePassword, config.JobProperties); + PathFile storePathFile = RemoteCertificateStore.SplitStorePathFile(config.CertificateStoreDetails.StorePath); + switch (config.OperationType) { case CertStoreOperationType.Add: @@ -62,7 +64,7 @@ public JobResult ProcessJob(ManagementJobConfiguration config) } certificateStore.LoadCertificateStore(certificateStoreSerializer, config.CertificateStoreDetails.Properties); certificateStore.AddCertificate((config.JobCertificate.Alias ?? new X509Certificate2(Convert.FromBase64String(config.JobCertificate.Contents), config.JobCertificate.PrivateKeyPassword).Thumbprint), config.JobCertificate.Contents, config.Overwrite, config.JobCertificate.PrivateKeyPassword); - certificateStore.SaveCertificateStore(certificateStoreSerializer.SerializeRemoteCertificateStore(certificateStore.GetCertificateStore(), config.CertificateStoreDetails.StorePath, config.CertificateStoreDetails.StorePassword, config.CertificateStoreDetails.Properties, certificateStore.RemoteHandler)); + certificateStore.SaveCertificateStore(certificateStoreSerializer.SerializeRemoteCertificateStore(certificateStore.GetCertificateStore(), storePathFile.Path, storePathFile.File, config.CertificateStoreDetails.StorePassword, config.CertificateStoreDetails.Properties, certificateStore.RemoteHandler)); logger.LogDebug($"END create Operation for {config.CertificateStoreDetails.StorePath} on {config.CertificateStoreDetails.ClientMachine}."); break; @@ -77,7 +79,7 @@ public JobResult ProcessJob(ManagementJobConfiguration config) { certificateStore.LoadCertificateStore(certificateStoreSerializer, config.CertificateStoreDetails.Properties); certificateStore.DeleteCertificateByAlias(config.JobCertificate.Alias); - certificateStore.SaveCertificateStore(certificateStoreSerializer.SerializeRemoteCertificateStore(certificateStore.GetCertificateStore(), config.CertificateStoreDetails.StorePath, config.CertificateStoreDetails.StorePassword, config.CertificateStoreDetails.Properties, certificateStore.RemoteHandler)); + certificateStore.SaveCertificateStore(certificateStoreSerializer.SerializeRemoteCertificateStore(certificateStore.GetCertificateStore(), storePathFile.Path, storePathFile.File, config.CertificateStoreDetails.StorePassword, config.CertificateStoreDetails.Properties, certificateStore.RemoteHandler)); } logger.LogDebug($"END Delete Operation for {config.CertificateStoreDetails.StorePath} on {config.CertificateStoreDetails.ClientMachine}."); break; diff --git a/RemoteFile/RemoteCertificateStore.cs b/RemoteFile/RemoteCertificateStore.cs index e20f46ec..7eb691b5 100644 --- a/RemoteFile/RemoteCertificateStore.cs +++ b/RemoteFile/RemoteCertificateStore.cs @@ -311,6 +311,21 @@ internal bool DoesStoreExist() return RemoteHandler.DoesFileExist(StorePath + StoreFileName); } + internal static PathFile SplitStorePathFile(string pathFileName) + { + try + { + string storePathFileName = pathFileName.Replace(@"\", @"/"); + int separatorIndex = storePathFileName.LastIndexOf(@"/"); + + return new PathFile() { Path = pathFileName.Substring(0, separatorIndex + 1), File = pathFileName.Substring(separatorIndex + 1) }; + } + catch (Exception ex) + { + throw new RemoteFileException($"Error attempting to parse certficate store path={pathFileName}.", ex); + } + } + private void Initialize() { logger.MethodEntry(LogLevel.Debug); @@ -418,24 +433,6 @@ private string[] GetAvailableDrives() return result.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); } - private PathFile SplitStorePathFile(string pathFileName) - { - logger.MethodEntry(LogLevel.Debug); - - try - { - string storePathFileName = pathFileName.Replace(@"\", @"/"); - int separatorIndex = storePathFileName.LastIndexOf(@"/"); - - logger.MethodExit(LogLevel.Debug); - return new PathFile() { Path = pathFileName.Substring(0, separatorIndex + 1), File = pathFileName.Substring(separatorIndex + 1) }; - } - catch (Exception ex) - { - throw new RemoteFileException($"Error attempting to parse certficate store path={StorePath}, file name={StoreFileName}.", ex); - } - } - private string FormatPath(string path) { logger.MethodEntry(LogLevel.Debug); From ea0f7e184a707ec2c3c5f905a7f438ceac1ab838 Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Wed, 19 Oct 2022 12:30:50 -0400 Subject: [PATCH 03/14] changes --- .../KDB/KDBCertificateStoreSerializer.cs | 8 ++++---- RemoteFile/RemoteHandlers/WinRMHandler.cs | 10 ++++------ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/RemoteFile/ImplementedStoreTypes/KDB/KDBCertificateStoreSerializer.cs b/RemoteFile/ImplementedStoreTypes/KDB/KDBCertificateStoreSerializer.cs index a44504f8..cd1df832 100644 --- a/RemoteFile/ImplementedStoreTypes/KDB/KDBCertificateStoreSerializer.cs +++ b/RemoteFile/ImplementedStoreTypes/KDB/KDBCertificateStoreSerializer.cs @@ -25,7 +25,7 @@ public Pkcs12Store DeserializeRemoteCertificateStore(byte[] storeContentBytes, s { logger.MethodEntry(LogLevel.Debug); - string kdbCommand = storePath.Substring(0, 1) == "/" ? "gskcapicmd" : "gsk8capicmd"; + string bashCommand = storePath.Substring(0, 1) == "/" ? "bash " : string.Empty; Pkcs12StoreBuilder storeBuilder = new Pkcs12StoreBuilder(); Pkcs12Store store = storeBuilder.Build(); @@ -35,7 +35,7 @@ public Pkcs12Store DeserializeRemoteCertificateStore(byte[] storeContentBytes, s remoteHandler.UploadCertificateFile(storePath, tempStoreFile, storeContentBytes); - string command = $"bash {kdbCommand} -keydb -convert -db '{storePath}{tempStoreFile}' -pw '{storePassword}' -type kdb -new_db '{storePath}{tempCertFile}' -new_pw '{storePassword}' -new_format p12"; + string command = $"{bashCommand}gskcapicmd -keydb -convert -db \"{storePath}{tempStoreFile}\" -pw \"{storePassword}\" -type kdb -new_db \"{storePath}{tempCertFile}\" -new_pw \"{storePassword}\" -new_format p12"; try { @@ -63,12 +63,12 @@ public List SerializeRemoteCertificateStore(Pkcs12Store cer logger.MethodEntry(LogLevel.Debug); List storeInfo = new List(); - string kdbCommand = storePath.Substring(0, 1) == "/" ? "gskcapicmd" : "gsk8capicmd"; + string bashCommand = storePath.Substring(0, 1) == "/" ? "bash " : string.Empty; string tempStoreFile = Guid.NewGuid().ToString().Replace("-", string.Empty) + ".kdb"; string tempCertFile = Guid.NewGuid().ToString().Replace("-", string.Empty) + ".p12"; - string command = $"bash {kdbCommand} -keydb -convert -db '{storePath}{tempCertFile}' -pw '{storePassword}' -type p12 -new_db '{storePath}{tempStoreFile}' -new_pw '{storePassword}' -new_format kdb"; + string command = $"{bashCommand}gskcapicmd -keydb -convert -db \"{storePath}{tempCertFile}\" -pw \"{storePassword}\" -type p12 -new_db \"{storePath}{tempStoreFile}\" -new_pw \"{storePassword}\" -new_format kdb"; try { diff --git a/RemoteFile/RemoteHandlers/WinRMHandler.cs b/RemoteFile/RemoteHandlers/WinRMHandler.cs index dbd3b217..3aec2932 100644 --- a/RemoteFile/RemoteHandlers/WinRMHandler.cs +++ b/RemoteFile/RemoteHandlers/WinRMHandler.cs @@ -20,9 +20,8 @@ namespace Keyfactor.Extensions.Orchestrator.RemoteFile.RemoteHandlers { class WinRMHandler : BaseRemoteHandler { - private const string IGNORED_ERROR1 = "importing keystore"; - private const string IGNORED_ERROR2 = "warning:"; - private const string IGNORED_ERROR3 = "certificate was added to keystore"; + private const string IGNORED_ERROR1 = "setupcmdline.bat"; + private const string IGNORED_ERROR2 = "operable program or batch file"; private Runspace runspace { get; set; } private WSManConnectionInfo connectionInfo { get; set; } @@ -115,9 +114,8 @@ public override string RunCommand(string commandText, object[] parameters, bool foreach (ErrorRecord errorRecord in errorRecords) { string error = errorRecord.ToString(); - if (error.ToLower().StartsWith(IGNORED_ERROR1) || - error.ToLower().Contains(IGNORED_ERROR2) || - error.ToLower().Contains(IGNORED_ERROR3)) + if (error.ToLower().Contains(IGNORED_ERROR1) + || error.ToLower().Contains(IGNORED_ERROR2)) { errors = null; break; From 24a58a30368852dad085e4ea6969f9ee8306ef21 Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Thu, 20 Oct 2022 12:46:57 -0400 Subject: [PATCH 04/14] changes --- Certificate Store Type CURL Scripts/KDB.curl | 40 ++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 Certificate Store Type CURL Scripts/KDB.curl diff --git a/Certificate Store Type CURL Scripts/KDB.curl b/Certificate Store Type CURL Scripts/KDB.curl new file mode 100644 index 00000000..c860650d --- /dev/null +++ b/Certificate Store Type CURL Scripts/KDB.curl @@ -0,0 +1,40 @@ +###CURL script to create KDB certificate store type + +###Replacement Variables - Manually replace these before running### +# {URL} - Base URL for your Keyfactor deployment +# {UserName} - User name with access to run Keyfactor APIs +# {UserPassword} - Password for the UserName above + +curl -X POST {URL}/keyfactorapi/certificatestoretypes -H "Content-Type: application/json" -H "x-keyfactor-requested-with: APIClient" -u {UserName}:{UserPassword} -d '{ + "Name": "RFKDB", + "ShortName": "RFKDB", + "Capability": "RFKDB", + "ServerRequired": true, + "BlueprintAllowed": false, + "CustomAliasAllowed": "Required", + "PowerShell": false, + "PrivateKeyAllowed": "Optional", + "SupportedOperations": { + "Add": true, + "Create": true, + "Discovery": true, + "Enrollment": false, + "Remove": true + }, + "PasswordOptions": { + "Style": "Default", + "EntrySupported": false, + "StoreRequired": true + }, + "Properties": [ + { + "Name": "LinuxFilePermissionsOnStoreCreation", + "DisplayName": "Linux File Permissions on Store Creation", + "Required": false, + "DependsOn": "", + "Type": "String", + "DefaultValue": "" + } + ], + "EntryParameters": [] +}' From 5e944632f9b1d13b9bb7463e37d812220db64a65 Mon Sep 17 00:00:00 2001 From: Lee Fine <50836957+leefine02@users.noreply.github.com> Date: Thu, 20 Oct 2022 12:49:11 -0400 Subject: [PATCH 05/14] Create CHANGELOG.md --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..ef53e061 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +v1.1 +- Add support for IBM Key Database (KDB) files + +v1.0 +- Initial Version From 41f90d0b3967150f953ab4a77bf317ca8fdf687c Mon Sep 17 00:00:00 2001 From: Lee Fine <50836957+leefine02@users.noreply.github.com> Date: Thu, 20 Oct 2022 14:54:24 -0400 Subject: [PATCH 06/14] Update readme_source.md --- readme_source.md | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/readme_source.md b/readme_source.md index 0c3ff6a4..fe5a8b96 100644 --- a/readme_source.md +++ b/readme_source.md @@ -4,6 +4,7 @@ The Remote File Orchestrator Extension is a multi-purpose integration that can r - Java Keystores of type JKS - PKCS12 files, including, but not limited to, Java keystores of type PKCS12 - PEM files +- IBM Key Database files (KDB) While the Keyfactor Universal Orchestrator (UO) can be installed on either Windows or Linux; likewise, the Remote File Orchestrator Extension can be used to manage certificate stores residing on both Windows and Linux servers. The supported configurations of Universal Orchestrator hosts and managed orchestrated servers are shown below: @@ -199,7 +200,38 @@ Entry Parameters Tab: - no additional entry parameters   -CURL script to automate certificate store type creation can be found [here](https://github.com/Keyfactor/remote-file-orchestrator/blob/initial-version/Certificate%20Store%20Type%20CURL%20Scripts/PEM.curl) +CURL script to automate certificate store type creation can be found [here](https://github.com/Keyfactor/remote-file-orchestrator/blob/initial-version/Certificate%20Store%20Type%20CURL%20Scripts/PEM.curl) + +  +  +************************************** +**RFKDB Certificate Store Type** +************************************** + +The RFKDB store type can be used to manage IBM Key Database Files (KDB) files. The IBM utility, GSKCAPICMD, is used to read and write certificates from and to the target store and is therefore required to be installed on the server where the Keyfactor Orchestrator Service is installed, and its location MUST be in the system $Path. + +Use cases supported: +1. One-to-many trust entries - A single certificate without a private key in a certificate store. Each certificate identified with a custom alias or certificate thumbprint. +2. One-to-many key entries - One-to-many certificates with private keys and optionally the full certificate chain. Each certificate identified with a custom alias or certificate thumbprint. +3. A mix of trust and key entries. + +**Specific Certificate Store Type Values** +*Basic Tab:* +- **Short Name** – Required. Suggested value - **RFKDB**. If you choose to use a different value you must make the corresponding modification to the manifest.json file (see "Remote File Orchestrator Extension Installation", step 6 above). + +*Advanced Tab:* +- **Supports Custom Alias** - Required. +- **Private Key Handling** - Optional. + +*Custom Fields Tab:* +- no adittional custom fields/parameters + +Entry Parameters Tab: +- no additional entry parameters + +  +CURL script to automate certificate store type creation can be found [here](https://github.com/Keyfactor/remote-file-orchestrator/blob/initial-version/Certificate%20Store%20Type%20CURL%20Scripts/KDB.curl) +     ## Creating Certificate Stores From f5eafec8c6cb6e20736879c54907afd6e422be39 Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Thu, 20 Oct 2022 18:55:05 +0000 Subject: [PATCH 07/14] Update generated README --- README.md | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7f2aca17..0ebcae2a 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ The Remote File Orchestrator Extension is a multi-purpose integration that can r - Java Keystores of type JKS - PKCS12 files, including, but not limited to, Java keystores of type PKCS12 - PEM files +- IBM Key Database files (KDB) While the Keyfactor Universal Orchestrator (UO) can be installed on either Windows or Linux; likewise, the Remote File Orchestrator Extension can be used to manage certificate stores residing on both Windows and Linux servers. The supported configurations of Universal Orchestrator hosts and managed orchestrated servers are shown below: @@ -234,7 +235,38 @@ Entry Parameters Tab: - no additional entry parameters   -CURL script to automate certificate store type creation can be found [here](https://github.com/Keyfactor/remote-file-orchestrator/blob/initial-version/Certificate%20Store%20Type%20CURL%20Scripts/PEM.curl) +CURL script to automate certificate store type creation can be found [here](https://github.com/Keyfactor/remote-file-orchestrator/blob/initial-version/Certificate%20Store%20Type%20CURL%20Scripts/PEM.curl) + +  +  +************************************** +**RFKDB Certificate Store Type** +************************************** + +The RFKDB store type can be used to manage IBM Key Database Files (KDB) files. The IBM utility, GSKCAPICMD, is used to read and write certificates from and to the target store and is therefore required to be installed on the server where the Keyfactor Orchestrator Service is installed, and its location MUST be in the system $Path. + +Use cases supported: +1. One-to-many trust entries - A single certificate without a private key in a certificate store. Each certificate identified with a custom alias or certificate thumbprint. +2. One-to-many key entries - One-to-many certificates with private keys and optionally the full certificate chain. Each certificate identified with a custom alias or certificate thumbprint. +3. A mix of trust and key entries. + +**Specific Certificate Store Type Values** +*Basic Tab:* +- **Short Name** – Required. Suggested value - **RFKDB**. If you choose to use a different value you must make the corresponding modification to the manifest.json file (see "Remote File Orchestrator Extension Installation", step 6 above). + +*Advanced Tab:* +- **Supports Custom Alias** - Required. +- **Private Key Handling** - Optional. + +*Custom Fields Tab:* +- no adittional custom fields/parameters + +Entry Parameters Tab: +- no additional entry parameters + +  +CURL script to automate certificate store type creation can be found [here](https://github.com/Keyfactor/remote-file-orchestrator/blob/initial-version/Certificate%20Store%20Type%20CURL%20Scripts/KDB.curl) +     ## Creating Certificate Stores From 50670e46ae8d3f6871802835496483463531251e Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Thu, 3 Nov 2022 09:26:23 -0400 Subject: [PATCH 08/14] changes --- CHANGELOG.md | 6 ++++++ RemoteFile/Discovery.cs | 1 + RemoteFile/InventoryBase.cs | 1 + RemoteFile/ManagementBase.cs | 1 + RemoteFile/RemoteCertificateStore.cs | 6 +----- RemoteFile/RemoteHandlers/SSHHandler.cs | 25 ++++++++++++++++--------- 6 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..4c4d1464 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,6 @@ +v1.1 +- Added support for KDB file type +- Extended error messaging for SSH/SFTP/SCP connection issues + +v1.0 +- Initial Version diff --git a/RemoteFile/Discovery.cs b/RemoteFile/Discovery.cs index e26b0248..164cf78e 100644 --- a/RemoteFile/Discovery.cs +++ b/RemoteFile/Discovery.cs @@ -44,6 +44,7 @@ public JobResult ProcessJob(DiscoveryJobConfiguration config, SubmitDiscoveryUpd try { + certificateStore.Initialize(); ApplicationSettings.Initialize(this.GetType().Assembly.Location); if (directoriesToSearch.Length == 0) diff --git a/RemoteFile/InventoryBase.cs b/RemoteFile/InventoryBase.cs index 94f20a8a..de371977 100644 --- a/RemoteFile/InventoryBase.cs +++ b/RemoteFile/InventoryBase.cs @@ -38,6 +38,7 @@ public JobResult ProcessJob(InventoryJobConfiguration config, SubmitInventoryUpd { ApplicationSettings.Initialize(this.GetType().Assembly.Location); certificateStore = new RemoteCertificateStore(config.CertificateStoreDetails.ClientMachine, config.ServerUsername, config.ServerPassword, config.CertificateStoreDetails.StorePath, config.CertificateStoreDetails.StorePassword, config.JobProperties); + certificateStore.Initialize(); certificateStore.LoadCertificateStore(certificateStoreSerializer, config.CertificateStoreDetails.Properties); List collections = certificateStore.GetCertificateChains(); diff --git a/RemoteFile/ManagementBase.cs b/RemoteFile/ManagementBase.cs index 73991502..71b7334b 100644 --- a/RemoteFile/ManagementBase.cs +++ b/RemoteFile/ManagementBase.cs @@ -48,6 +48,7 @@ public JobResult ProcessJob(ManagementJobConfiguration config) ApplicationSettings.Initialize(this.GetType().Assembly.Location); certificateStore = new RemoteCertificateStore(config.CertificateStoreDetails.ClientMachine, config.ServerUsername, config.ServerPassword, config.CertificateStoreDetails.StorePath, config.CertificateStoreDetails.StorePassword, config.JobProperties); + certificateStore.Initialize(); PathFile storePathFile = RemoteCertificateStore.SplitStorePathFile(config.CertificateStoreDetails.StorePath); diff --git a/RemoteFile/RemoteCertificateStore.cs b/RemoteFile/RemoteCertificateStore.cs index 7eb691b5..6ca4712a 100644 --- a/RemoteFile/RemoteCertificateStore.cs +++ b/RemoteFile/RemoteCertificateStore.cs @@ -79,8 +79,6 @@ internal RemoteCertificateStore(string server, string serverId, string serverPas } logger.LogDebug("Store path valid"); - Initialize(); - logger.MethodExit(LogLevel.Debug); } @@ -94,8 +92,6 @@ internal RemoteCertificateStore(string server, string serverId, string serverPas ServerPassword = serverPassword ?? string.Empty; ServerType = serverType; - Initialize(); - logger.MethodExit(LogLevel.Debug); } @@ -326,7 +322,7 @@ internal static PathFile SplitStorePathFile(string pathFileName) } } - private void Initialize() + internal void Initialize() { logger.MethodEntry(LogLevel.Debug); diff --git a/RemoteFile/RemoteHandlers/SSHHandler.cs b/RemoteFile/RemoteHandlers/SSHHandler.cs index a6b77b00..f756385c 100644 --- a/RemoteFile/RemoteHandlers/SSHHandler.cs +++ b/RemoteFile/RemoteHandlers/SSHHandler.cs @@ -67,9 +67,16 @@ internal SSHHandler(string server, string serverLogin, string serverPassword) public override void Initialize() { _logger.MethodEntry(LogLevel.Debug); - - sshClient = new SshClient(Connection); - sshClient.Connect(); + + try + { + sshClient = new SshClient(Connection); + sshClient.Connect(); + } + catch (Exception ex) + { + throw new RemoteFileException($"Error making a SSH connection to remote server {Connection.Host}, for user {Connection.Username}. Please contact your company's system administrator to verify connection and permission settings.", ex); + } _logger.MethodExit(LogLevel.Debug); } @@ -163,7 +170,7 @@ public override void UploadCertificateFile(string path, string fileName, byte[] if (ApplicationSettings.FileTransferProtocol == ApplicationSettings.FileTransferProtocolEnum.Both) _logger.LogDebug($"SCP upload failed. Attempting with SFTP protocol..."); else - throw ex; + throw new RemoteFileException("Error attempting SCP file transfer to {Connection.Host} using login {Connection.Username} and connection method {Connection.AuthenticationMethods[0].Name}. Please contact your company's system administrator to verify connection and permission settings.", ex); } finally { @@ -190,7 +197,7 @@ public override void UploadCertificateFile(string path, string fileName, byte[] { _logger.LogError("Exception during SFTP upload..."); _logger.LogError($"Upload Exception: {RemoteFileException.FlattenExceptionMessages(ex, ex.Message)}"); - throw ex; + throw new RemoteFileException("Error attempting SFTP file transfer to {Connection.Host} using login {Connection.Username} and connection method {Connection.AuthenticationMethods[0].Name}. Please contact your company's system administrator to verify connection and permission settings.", ex); } finally { @@ -235,7 +242,7 @@ public override byte[] DownloadCertificateFile(string path) { try { - _logger.LogDebug($"SCP connection attempt to {Connection.Host} using login {Connection.Username} and connection method {Connection.AuthenticationMethods[0].Name}"); + _logger.LogDebug($"SCP connection attempt from {Connection.Host} using login {Connection.Username} and connection method {Connection.AuthenticationMethods[0].Name}"); client.Connect(); using (MemoryStream stream = new MemoryStream()) @@ -252,7 +259,7 @@ public override byte[] DownloadCertificateFile(string path) if (ApplicationSettings.FileTransferProtocol == ApplicationSettings.FileTransferProtocolEnum.Both) _logger.LogDebug($"SCP download failed. Attempting with SFTP protocol..."); else - throw ex; + throw new RemoteFileException($"Error attempting SCP file transfer from {Connection.Host} using login {Connection.Username} and connection method {Connection.AuthenticationMethods[0].Name}. Please contact your company's system administrator to verify connection and permission settings.", ex); } finally { @@ -267,7 +274,7 @@ public override byte[] DownloadCertificateFile(string path) { try { - _logger.LogDebug($"SFTP connection attempt to {Connection.Host} using login {Connection.Username} and connection method {Connection.AuthenticationMethods[0].Name}"); + _logger.LogDebug($"SFTP connection attempt from {Connection.Host} using login {Connection.Username} and connection method {Connection.AuthenticationMethods[0].Name}"); client.Connect(); using (MemoryStream stream = new MemoryStream()) @@ -280,7 +287,7 @@ public override byte[] DownloadCertificateFile(string path) { _logger.LogError("Exception during SFTP download..."); _logger.LogError($"Download Exception: {RemoteFileException.FlattenExceptionMessages(ex, ex.Message)}"); - throw ex; + throw new RemoteFileException($"Error attempting SFTP file transfer from {Connection.Host} using login {Connection.Username} and connection method {Connection.AuthenticationMethods[0].Name}. Please contact your company's system administrator to verify connection and permission settings.", ex); } finally { From f6bc4caca58b3284e486a3319e28dd72d04a27b7 Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Thu, 3 Nov 2022 09:31:39 -0400 Subject: [PATCH 09/14] changes --- readme_source.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/readme_source.md b/readme_source.md index 0c3ff6a4..2703b89d 100644 --- a/readme_source.md +++ b/readme_source.md @@ -1,4 +1,4 @@ - + ## Overview The Remote File Orchestrator Extension is a multi-purpose integration that can remotely manage a variety of file-based certificate stores and can easily be extended to manage others. The certificate store types that can be managed in the current version are: - Java Keystores of type JKS @@ -18,12 +18,12 @@ This orchestrator extension makes use of an SSH connection to communicate remote   ## Versioning -The version number of a the Remote File Orchestrator Extension can be verified by right clicking on the n the Extensions/RemoteFile installation folder, selecting Properties, and then clicking on the Details tab. +The version number of a the Remote File Orchestrator Extension can be verified by right clicking on the RemoteFile.dll file in the Extensions/RemoteFile installation folder, selecting Properties, and then clicking on the Details tab.     ## Keyfactor Version Supported -The Remote File Orchestrator Extension has been tested against Keyfactor Universal Orchestrator version 9.5, but should work against earlier or later versions of the Keyfactor Universal Orchestrator. +The Remote File Orchestrator Extension has been tested against Keyfactor Universal Orchestrator version 9.9, but should work against earlier or later versions of the Keyfactor Universal Orchestrator.     ## Security Considerations @@ -44,6 +44,8 @@ The Remote File Orchestrator Extension has been tested against Keyfactor Univers 2. When creating/configuring a certificate store in Keyfactor Command, you will see a "Change Credentials" link after entering in the destination client machine (IP or DNS). This link **must** be clicked on to present the credentials dialog. However, it is not required that you enter separate credentials. Simply click SAVE in the resulting dialog without entering in credentials to use the credentials that the Keyfactor Orchestrator Service is running under. Alternatively, you may enter separate credentials into this dialog and use those to connect to the orchestrated server. +Please consult with your company's system administrator for more information on configuring SSH/SFTP/SCP or WinRM in your environment. + **SSH Key-Based Authentiation** 1. When creating a Keyfactor certificate store for the remote file orchestrator extension (see "Creating Certificate Stores" later in this README, you may supply either a user id and password for the certificate store credentials (directly or through one of Keyfactor Command's PAM integrations), or a user id and SSH private key. Both PKCS#1 (BEGIN RSA PRIVATE KEY) and PKCS#8 (BEGIN PRIVATE KEY) formats are supported for the SSH private key. If using the normal Keyfactor Command credentials dialog without PAM integration, just copy and paste the full SSH private key into the Password textbox.   From 44cec6d219189a04b48895f7680e7caa134f6540 Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Thu, 3 Nov 2022 09:38:13 -0400 Subject: [PATCH 10/14] changes --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0c21469..da2afb13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ v1.1 -- Added support for KDB file type +- Added support for IBM Key Database (KDB) files - Extended error messaging for SSH/SFTP/SCP connection issues v1.0 From 218464cf3452a0378d8195d346b8c15f928f99ba Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Thu, 3 Nov 2022 13:38:53 +0000 Subject: [PATCH 11/14] Update generated README --- README.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0ebcae2a..ad15d02e 100644 --- a/README.md +++ b/README.md @@ -6,16 +6,18 @@ The Remote File Orchestrator allows for the remote management of file-based cert ## About the Keyfactor Universal Orchestrator Capability -This repository contains a Universal Orchestrator Extension which is a plugin to the Keyfactor Universal Orchestrator. Within the Keyfactor Platform, Orchestrators are used to manage “certificate stores” — collections of certificates and roots of trust that are found within and used by various applications. +This repository contains a Universal Orchestrator Capability which is a plugin to the Keyfactor Universal Orchestrator. Within the Keyfactor Platform, Orchestrators are used to manage “certificate stores” — collections of certificates and roots of trust that are found within and used by various applications. The Universal Orchestrator is part of the Keyfactor software distribution and is available via the Keyfactor customer portal. For general instructions on installing Capabilities, see the “Keyfactor Command Orchestrator Installation and Configuration Guide” section of the Keyfactor documentation. For configuration details of this specific Capability, see below in this readme. The Universal Orchestrator is the successor to the Windows Orchestrator. This Capability plugin only works with the Universal Orchestrator and does not work with the Windows Orchestrator. ---- +--- + + ## Platform Specific Notes @@ -33,7 +35,8 @@ The Keyfactor Universal Orchestrator may be installed on either Windows or Linux --- - + + ## Overview The Remote File Orchestrator Extension is a multi-purpose integration that can remotely manage a variety of file-based certificate stores and can easily be extended to manage others. The certificate store types that can be managed in the current version are: - Java Keystores of type JKS @@ -54,12 +57,12 @@ This orchestrator extension makes use of an SSH connection to communicate remote   ## Versioning -The version number of a the Remote File Orchestrator Extension can be verified by right clicking on the n the Extensions/RemoteFile installation folder, selecting Properties, and then clicking on the Details tab. +The version number of a the Remote File Orchestrator Extension can be verified by right clicking on the RemoteFile.dll file in the Extensions/RemoteFile installation folder, selecting Properties, and then clicking on the Details tab.     ## Keyfactor Version Supported -The Remote File Orchestrator Extension has been tested against Keyfactor Universal Orchestrator version 9.5, but should work against earlier or later versions of the Keyfactor Universal Orchestrator. +The Remote File Orchestrator Extension has been tested against Keyfactor Universal Orchestrator version 9.9, but should work against earlier or later versions of the Keyfactor Universal Orchestrator.     ## Security Considerations @@ -80,6 +83,8 @@ The Remote File Orchestrator Extension has been tested against Keyfactor Univers 2. When creating/configuring a certificate store in Keyfactor Command, you will see a "Change Credentials" link after entering in the destination client machine (IP or DNS). This link **must** be clicked on to present the credentials dialog. However, it is not required that you enter separate credentials. Simply click SAVE in the resulting dialog without entering in credentials to use the credentials that the Keyfactor Orchestrator Service is running under. Alternatively, you may enter separate credentials into this dialog and use those to connect to the orchestrated server. +Please consult with your company's system administrator for more information on configuring SSH/SFTP/SCP or WinRM in your environment. + **SSH Key-Based Authentiation** 1. When creating a Keyfactor certificate store for the remote file orchestrator extension (see "Creating Certificate Stores" later in this README, you may supply either a user id and password for the certificate store credentials (directly or through one of Keyfactor Command's PAM integrations), or a user id and SSH private key. Both PKCS#1 (BEGIN RSA PRIVATE KEY) and PKCS#8 (BEGIN PRIVATE KEY) formats are supported for the SSH private key. If using the normal Keyfactor Command credentials dialog without PAM integration, just copy and paste the full SSH private key into the Password textbox.   From 28a238474e363879a907de212d0f0ecd9d61648d Mon Sep 17 00:00:00 2001 From: Lee Fine Date: Fri, 4 Nov 2022 12:59:57 -0400 Subject: [PATCH 12/14] changes --- RemoteFile/Discovery.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RemoteFile/Discovery.cs b/RemoteFile/Discovery.cs index 164cf78e..1f2bbc82 100644 --- a/RemoteFile/Discovery.cs +++ b/RemoteFile/Discovery.cs @@ -32,7 +32,7 @@ public JobResult ProcessJob(DiscoveryJobConfiguration config, SubmitDiscoveryUpd logger.LogDebug($" {keyValue.Key}: {keyValue.Value}"); } - string[] directoriesToSearch = config.JobProperties["dirs"].ToString().Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + string[] directoriesToSearch = config.JobProperties["dirs"].ToString().Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); string[] extensionsToSearch = config.JobProperties["extensions"].ToString().Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); string[] ignoredDirs = config.JobProperties["ignoreddirs"].ToString().Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); string[] filesTosearch = config.JobProperties["patterns"].ToString().Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); From dbae712f4222c43fb7656418d9c9c2bfef2fd743 Mon Sep 17 00:00:00 2001 From: kfadmin Date: Fri, 4 Nov 2022 17:21:33 +0000 Subject: [PATCH 13/14] changes --- RemoteFile/ApplicationSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RemoteFile/ApplicationSettings.cs b/RemoteFile/ApplicationSettings.cs index a39f043c..a4d78407 100644 --- a/RemoteFile/ApplicationSettings.cs +++ b/RemoteFile/ApplicationSettings.cs @@ -7,7 +7,7 @@ using Keyfactor.Logging; -namespace Keyfactor.Extensions.Orchestrator.RemoteFile +namespace Keyfactor.Extensions.Orchestrator.RemoteFile { class ApplicationSettings { From c4cc789b26287b04f703597e10782f7dc98053d5 Mon Sep 17 00:00:00 2001 From: Lee Fine <50836957+leefine02@users.noreply.github.com> Date: Thu, 10 Nov 2022 14:04:47 -0500 Subject: [PATCH 14/14] Update ManagementBase.cs --- RemoteFile/ManagementBase.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/RemoteFile/ManagementBase.cs b/RemoteFile/ManagementBase.cs index 885b7e00..9c374ce8 100644 --- a/RemoteFile/ManagementBase.cs +++ b/RemoteFile/ManagementBase.cs @@ -52,8 +52,6 @@ public JobResult ProcessJob(ManagementJobConfiguration config) PathFile storePathFile = RemoteCertificateStore.SplitStorePathFile(config.CertificateStoreDetails.StorePath); - PathFile storePathFile = RemoteCertificateStore.SplitStorePathFile(config.CertificateStoreDetails.StorePath); - switch (config.OperationType) { case CertStoreOperationType.Add: @@ -131,4 +129,4 @@ private void CreateStore(ManagementJobConfiguration config) certificateStore.CreateCertificateStore(config.CertificateStoreDetails.StorePath, linuxFilePermissions); } } -} \ No newline at end of file +}