Skip to content

Commit

Permalink
Merge 789b32c into 3bc366f
Browse files Browse the repository at this point in the history
  • Loading branch information
leefine02 committed Jul 26, 2024
2 parents 3bc366f + 789b32c commit 51f86ee
Show file tree
Hide file tree
Showing 12 changed files with 98 additions and 50 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
v2.8.0
- Added new custom field - Remove Root Certificate from Chain - to allow adding certificate entries with the root CA certificate removed from the chain.
- Added SSH KeyboardInteractive Authentication support if Password Authentication is not enabled.

v2.7.0
- Modified RFJKS store type support java keystores of both PKCS12 and JKS
- Added support for OpenSSH private keys for SSH authentication
Expand Down
13 changes: 10 additions & 3 deletions README.md

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion RemoteFile/InventoryBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public JobResult ProcessJob(InventoryJobConfiguration config, SubmitInventoryUpd
logger.LogDebug($"Begin {config.Capability} for job id {config.JobId}...");
logger.LogDebug($"Server: { config.CertificateStoreDetails.ClientMachine }");
logger.LogDebug($"Store Path: { config.CertificateStoreDetails.StorePath }");
logger.LogDebug($"Store Properties: {config.CertificateStoreDetails.Properties.ToString()}");
logger.LogDebug($"Job Properties:");
foreach (KeyValuePair<string, object> keyValue in config.JobProperties ?? new Dictionary<string,object>())
{
Expand All @@ -54,7 +55,7 @@ public JobResult ProcessJob(InventoryJobConfiguration config, SubmitInventoryUpd

certificateStore = new RemoteCertificateStore(config.CertificateStoreDetails.ClientMachine, userName, userPassword, config.CertificateStoreDetails.StorePath, storePassword, config.JobProperties);
certificateStore.Initialize(sudoImpersonatedUser);
certificateStore.LoadCertificateStore(certificateStoreSerializer, config.CertificateStoreDetails.Properties, true);
certificateStore.LoadCertificateStore(certificateStoreSerializer, true);

List<X509Certificate2Collection> collections = certificateStore.GetCertificateChains();

Expand Down
14 changes: 9 additions & 5 deletions RemoteFile/ManagementBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ public JobResult ProcessJob(ManagementJobConfiguration config)
{
ILogger logger = LogHandler.GetClassLogger(this.GetType());
logger.LogDebug($"Begin {config.Capability} for job id {config.JobId}...");
logger.LogDebug($"Server: { config.CertificateStoreDetails.ClientMachine }");
logger.LogDebug($"Store Path: { config.CertificateStoreDetails.StorePath }");
logger.LogDebug($"Server: {config.CertificateStoreDetails.ClientMachine}");
logger.LogDebug($"Store Path: {config.CertificateStoreDetails.StorePath}");
logger.LogDebug($"Store Properties: {config.CertificateStoreDetails.Properties.ToString()}");
logger.LogDebug($"Job Properties:");
foreach (KeyValuePair<string, object> keyValue in config.JobProperties == null ? new Dictionary<string, object>() : config.JobProperties)
{
Expand All @@ -50,6 +51,9 @@ public JobResult ProcessJob(ManagementJobConfiguration config)
string sudoImpersonatedUser = properties.SudoImpersonatedUser == null || string.IsNullOrEmpty(properties.SudoImpersonatedUser.Value) ?
ApplicationSettings.DefaultSudoImpersonatedUser :
properties.SudoImpersonatedUser.Value;
bool removeRootCertificate = properties.RemoveRootCertificate == null || string.IsNullOrEmpty(properties.RemoveRootCertificate.Value) ?
false :
Convert.ToBoolean(properties.RemoveRootCertificate.Value);

certificateStore = new RemoteCertificateStore(config.CertificateStoreDetails.ClientMachine, userName, userPassword, config.CertificateStoreDetails.StorePath, storePassword, config.JobProperties);
certificateStore.Initialize(sudoImpersonatedUser);
Expand All @@ -67,8 +71,8 @@ public JobResult ProcessJob(ManagementJobConfiguration config)
else
throw new RemoteFileException($"Certificate store {config.CertificateStoreDetails.StorePath} does not exist on server {config.CertificateStoreDetails.ClientMachine}.");
}
certificateStore.LoadCertificateStore(certificateStoreSerializer, config.CertificateStoreDetails.Properties, false);
certificateStore.AddCertificate((config.JobCertificate.Alias ?? new X509Certificate2(Convert.FromBase64String(config.JobCertificate.Contents), config.JobCertificate.PrivateKeyPassword, X509KeyStorageFlags.EphemeralKeySet).Thumbprint), config.JobCertificate.Contents, config.Overwrite, config.JobCertificate.PrivateKeyPassword);
certificateStore.LoadCertificateStore(certificateStoreSerializer, false);
certificateStore.AddCertificate((config.JobCertificate.Alias ?? new X509Certificate2(Convert.FromBase64String(config.JobCertificate.Contents), config.JobCertificate.PrivateKeyPassword, X509KeyStorageFlags.EphemeralKeySet).Thumbprint), config.JobCertificate.Contents, config.Overwrite, config.JobCertificate.PrivateKeyPassword, removeRootCertificate);
certificateStore.SaveCertificateStore(certificateStoreSerializer.SerializeRemoteCertificateStore(certificateStore.GetCertificateStore(), storePathFile.Path, storePathFile.File, storePassword, certificateStore.RemoteHandler));

logger.LogDebug($"END add Operation for {config.CertificateStoreDetails.StorePath} on {config.CertificateStoreDetails.ClientMachine}.");
Expand All @@ -82,7 +86,7 @@ public JobResult ProcessJob(ManagementJobConfiguration config)
}
else
{
certificateStore.LoadCertificateStore(certificateStoreSerializer, config.CertificateStoreDetails.Properties, false);
certificateStore.LoadCertificateStore(certificateStoreSerializer, false);
certificateStore.DeleteCertificateByAlias(config.JobCertificate.Alias);
certificateStore.SaveCertificateStore(certificateStoreSerializer.SerializeRemoteCertificateStore(certificateStore.GetCertificateStore(), storePathFile.Path, storePathFile.File, storePassword, certificateStore.RemoteHandler));
}
Expand Down
7 changes: 5 additions & 2 deletions RemoteFile/ReenrollmentBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ public JobResult ProcessJobToDo(ReenrollmentJobConfiguration config, SubmitReenr
string sudoImpersonatedUser = properties.SudoImpersonatedUser == null || string.IsNullOrEmpty(properties.SudoImpersonatedUser.Value) ?
ApplicationSettings.DefaultSudoImpersonatedUser :
properties.SudoImpersonatedUser.Value;
bool removeRootCertificate = properties.RemoveRootCertificate == null || string.IsNullOrEmpty(properties.RemoveRootCertificate.Value) ?
false :
Convert.ToBoolean(properties.RemoveRootCertificate.Value);
bool createCSROnDevice = properties.CreateCSROnDevice == null || string.IsNullOrEmpty(properties.CreateCSROnDevice.Value) ?
ApplicationSettings.CreateCSROnDevice :
Convert.ToBoolean(properties.CreateCSROnDevice.Value);
Expand Down Expand Up @@ -118,8 +121,8 @@ public JobResult ProcessJobToDo(ReenrollmentJobConfiguration config, SubmitReenr
cert = keyTypeEnum == SupportedKeyTypeEnum.RSA ? cert.CopyWithPrivateKey((RSA)alg) : cert.CopyWithPrivateKey((ECDsa)alg);

// save certificate
certificateStore.LoadCertificateStore(certificateStoreSerializer, config.CertificateStoreDetails.Properties, false);
certificateStore.AddCertificate((alias ?? cert.Thumbprint), Convert.ToBase64String(cert.Export(X509ContentType.Pfx)), overwrite, null);
certificateStore.LoadCertificateStore(certificateStoreSerializer, false);
certificateStore.AddCertificate((alias ?? cert.Thumbprint), Convert.ToBase64String(cert.Export(X509ContentType.Pfx)), overwrite, null, removeRootCertificate);
certificateStore.SaveCertificateStore(certificateStoreSerializer.SerializeRemoteCertificateStore(certificateStore.GetCertificateStore(), storePathFile.Path, storePathFile.File, storePassword, certificateStore.RemoteHandler));

logger.LogDebug($"END add Operation for {config.CertificateStoreDetails.StorePath} on {config.CertificateStoreDetails.ClientMachine}.");
Expand Down
39 changes: 34 additions & 5 deletions RemoteFile/RemoteCertificateStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ internal RemoteCertificateStore(string server, string serverId, string serverPas
logger.MethodExit(LogLevel.Debug);
}

internal void LoadCertificateStore(ICertificateStoreSerializer certificateStoreSerializer, string storeProperties, bool isInventory)
internal void LoadCertificateStore(ICertificateStoreSerializer certificateStoreSerializer, bool isInventory)
{
logger.MethodEntry(LogLevel.Debug);

Expand Down Expand Up @@ -242,7 +242,7 @@ internal void CreateCertificateStore(ICertificateStoreSerializer certificateStor
logger.MethodExit(LogLevel.Debug);
}

internal void AddCertificate(string alias, string certificateEntry, bool overwrite, string pfxPassword)
internal void AddCertificate(string alias, string certificateEntry, bool overwrite, string pfxPassword, bool removeRootCertificate)
{
logger.MethodEntry(LogLevel.Debug);

Expand All @@ -251,7 +251,9 @@ internal void AddCertificate(string alias, string certificateEntry, bool overwri
Pkcs12StoreBuilder storeBuilder = new Pkcs12StoreBuilder();
Pkcs12Store certs = storeBuilder.Build();

byte[] newCertBytes = Convert.FromBase64String(certificateEntry);
byte[] newCertBytes = removeRootCertificate && !string.IsNullOrEmpty(pfxPassword) ?
RemoveRootCertificate(Convert.FromBase64String(certificateEntry), pfxPassword) :
Convert.FromBase64String(certificateEntry);

Pkcs12Store newEntry = storeBuilder.Build();

Expand Down Expand Up @@ -454,11 +456,38 @@ internal void Initialize(string sudoImpersonatedUser)
else
RemoteHandler = new WinRMHandler(Server, ServerId, ServerPassword, treatAsLocal);

RemoteHandler.Initialize();

logger.MethodExit(LogLevel.Debug);
}

private byte[] RemoveRootCertificate(byte[] binCert, string password)
{
Pkcs12StoreBuilder storeBuilder = new Pkcs12StoreBuilder();
Pkcs12Store store = storeBuilder.Build();
Pkcs12Store store2 = storeBuilder.Build();

byte[] rtnCert = new byte[1];

using (MemoryStream ms = new MemoryStream(binCert))
{
store.Load(ms, password.ToCharArray());
}

foreach (string alias in store.Aliases)
{
X509CertificateEntry[] chain = store.GetCertificateChain(alias);
chain = chain.Where(p => p.Certificate.SubjectDN.ToString() != p.Certificate.IssuerDN.ToString()).ToArray();
store2.SetKeyEntry(alias, store.GetKey(alias), chain);

using (MemoryStream ms = new MemoryStream())
{
store2.Save(ms, password.ToCharArray(), new SecureRandom());
rtnCert = ms.ToArray();
}
}

return rtnCert;
}

private bool AreValuesSafeRegex(string[] values)
{
bool valueIsSafe = true;
Expand Down
2 changes: 0 additions & 2 deletions RemoteFile/RemoteHandlers/BaseRemoteHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ 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 abstract void Initialize();

public abstract void Terminate();

public abstract string RunCommand(string commandText, object[] arguments, bool withSudo, string[] passwordsToMaskInLog);
Expand Down
2 changes: 0 additions & 2 deletions RemoteFile/RemoteHandlers/IRemoteHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ namespace Keyfactor.Extensions.Orchestrator.RemoteFile.RemoteHandlers
/// </summary>
interface IRemoteHandler
{
void Initialize();

void Terminate();

string RunCommand(string commandText, object[] arguments, bool withSudo, string[] passwordsToMaskInLog);
Expand Down
6 changes: 0 additions & 6 deletions RemoteFile/RemoteHandlers/LinuxLocalHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,6 @@ class LinuxLocalHandler : BaseRemoteHandler
private Command BaseCommand { get; set; }

internal LinuxLocalHandler()
{
_logger.MethodEntry(LogLevel.Debug);
_logger.MethodExit(LogLevel.Debug);
}

public override void Initialize()
{
_logger.MethodEntry(LogLevel.Debug);

Expand Down
34 changes: 22 additions & 12 deletions RemoteFile/RemoteHandlers/SSHHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
using Keyfactor.Logging;
using Keyfactor.PKI.PrivateKeys;
using Keyfactor.PKI.PEM;
using static Microsoft.ApplicationInsights.MetricDimensionNames.TelemetryContext;
using Renci.SshNet.Common;
using Org.BouncyCastle.Bcpg;

namespace Keyfactor.Extensions.Orchestrator.RemoteFile.RemoteHandlers
{
Expand All @@ -26,6 +29,8 @@ class SSHHandler : BaseRemoteHandler
private ConnectionInfo Connection { get; set; }
private string SudoImpersonatedUser { get; set; }
private bool IsStoreServerLinux { get; set; }
private string UserId { get; set; }
private string Password { get; set; }
private SshClient sshClient;

internal SSHHandler(string server, string serverLogin, string serverPassword, bool isStoreServerLinux, string sudoImpersonatedUser)
Expand All @@ -35,11 +40,14 @@ internal SSHHandler(string server, string serverLogin, string serverPassword, bo
Server = server;
SudoImpersonatedUser = sudoImpersonatedUser;
IsStoreServerLinux = isStoreServerLinux;
UserId = serverLogin;
Password = serverPassword;

List<AuthenticationMethod> authenticationMethods = new List<AuthenticationMethod>();
if (serverPassword.Length < PASSWORD_LENGTH_MAX)
{
authenticationMethods.Add(new PasswordAuthenticationMethod(serverLogin, serverPassword));
KeyboardInteractiveAuthenticationMethod keyboardAuthentication = new KeyboardInteractiveAuthenticationMethod(UserId);
keyboardAuthentication.AuthenticationPrompt += KeyboardAuthentication_AuthenticationPrompt;
Connection = new ConnectionInfo(server, serverLogin, new PasswordAuthenticationMethod(serverLogin, serverPassword), keyboardAuthentication);
}
else
{
Expand All @@ -60,18 +68,9 @@ internal SSHHandler(string server, string serverLogin, string serverPassword, bo
}
}

authenticationMethods.Add(new PrivateKeyAuthenticationMethod(serverLogin, privateKeyFile));
Connection = new ConnectionInfo(server, serverLogin, new PrivateKeyAuthenticationMethod(serverLogin, privateKeyFile));
}

Connection = new ConnectionInfo(server, serverLogin, authenticationMethods.ToArray());

_logger.MethodExit(LogLevel.Debug);
}

public override void Initialize()
{
_logger.MethodEntry(LogLevel.Debug);

try
{
sshClient = new SshClient(Connection);
Expand Down Expand Up @@ -382,6 +381,17 @@ public override void RemoveCertificateFile(string path, string fileName)
RunCommand($"rm {path}{fileName}", null, ApplicationSettings.UseSudo, null);
}

private void KeyboardAuthentication_AuthenticationPrompt(object sender, AuthenticationPromptEventArgs e)
{
_logger.MethodEntry(LogLevel.Debug);
foreach (AuthenticationPrompt prompt in e.Prompts)
{
if (prompt.Request.StartsWith("Password"))
prompt.Response = Password;
}
_logger.MethodExit(LogLevel.Debug);
}

private void SplitStorePathFile(string pathFileName, out string path, out string fileName)
{
_logger.MethodEntry(LogLevel.Debug);
Expand Down
11 changes: 2 additions & 9 deletions RemoteFile/RemoteHandlers/WinRMHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,6 @@ internal WinRMHandler(string server, string serverLogin, string serverPassword,
}
}

_logger.MethodExit(LogLevel.Debug);
}

public override void Initialize()
{
_logger.MethodEntry(LogLevel.Debug);

try
{
if (RunLocal)
Expand All @@ -69,8 +62,8 @@ public override void Initialize()

catch (Exception ex)
{
_logger.LogError($"Exception during Initialize...{RemoteFileException.FlattenExceptionMessages(ex, ex.Message)}");
throw ex;
_logger.LogError($"Exception attempting to connect to server...{RemoteFileException.FlattenExceptionMessages(ex, ex.Message)}");
throw;
}

_logger.MethodExit(LogLevel.Debug);
Expand Down
Loading

0 comments on commit 51f86ee

Please sign in to comment.