Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 0 additions & 27 deletions .github/workflows/keyfactor-merge-store-types.yml

This file was deleted.

19 changes: 13 additions & 6 deletions .github/workflows/keyfactor-starter-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,17 @@ on:

jobs:
call-starter-workflow:
uses: keyfactor/actions/.github/workflows/starter.yml@3.1.2
uses: keyfactor/actions/.github/workflows/starter.yml@v4
with:
command_token_url: ${{ vars.COMMAND_TOKEN_URL }} # Only required for doctool generated screenshots
command_hostname: ${{ vars.COMMAND_HOSTNAME }} # Only required for doctool generated screenshots
command_base_api_path: ${{ vars.COMMAND_API_PATH }} # Only required for doctool generated screenshots
secrets:
token: ${{ secrets.V2BUILDTOKEN}}
APPROVE_README_PUSH: ${{ secrets.APPROVE_README_PUSH}}
gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }}
gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }}
scan_token: ${{ secrets.SAST_TOKEN }}
token: ${{ secrets.V2BUILDTOKEN}} # REQUIRED
gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }} # Only required for golang builds
gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }} # Only required for golang builds
scan_token: ${{ secrets.SAST_TOKEN }} # REQUIRED
entra_username: ${{ secrets.DOCTOOL_ENTRA_USERNAME }} # Only required for doctool generated screenshots
entra_password: ${{ secrets.DOCTOOL_ENTRA_PASSWD }} # Only required for doctool generated screenshots
command_client_id: ${{ secrets.COMMAND_CLIENT_ID }} # Only required for doctool generated screenshots
command_client_secret: ${{ secrets.COMMAND_CLIENT_SECRET }} # Only required for doctool generated screenshots
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
v2.12.0
- Added config.json setting and its override store level custom field - AllowShellCommands. If "N" (default "Y"), SFTP will be used to create stores and move files on Linux-based certificate store servers. No Linux shell commands will be used in the integration.

v2.11.5
- Bug Fix: Rare race condition loading config settings when multiple RemoteFile jobs are running simultaneously on the same orchestrator
- Documentation update to better list out what Linux commands get executed under what situations in Requirements & Prerequisites section
Expand Down
45 changes: 44 additions & 1 deletion README.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions RemoteFile/ApplicationSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
public static string DefaultSudoImpersonatedUser { get { return configuration.ContainsKey("DefaultSudoImpersonatedUser") ? configuration["DefaultSudoImpersonatedUser"] : DEFAULT_SUDO_IMPERSONATION_SETTING; } }
public static bool CreateCSROnDevice { get { return configuration.ContainsKey("CreateCSROnDevice") ? configuration["CreateCSROnDevice"]?.ToUpper() == "Y" : false; } }
public static string TempFilePathForODKG { get { return configuration.ContainsKey("TempFilePathForODKG") ? configuration["TempFilePathForODKG"] : string.Empty; } }
public static bool UseShellCommands { get { return configuration.ContainsKey("UseShellCommands") ? configuration["UseShellCommands"]?.ToUpper() == "Y" : true; } }
public static int SSHPort
{
get
Expand Down Expand Up @@ -72,7 +73,7 @@
protocolNames += protocolName + ", ";
}
protocolNames = protocolNames.Substring(0, protocolNames.Length - 2);
string? protocolValue = configuration["FileTransferProtocol"];

Check warning on line 76 in RemoteFile/ApplicationSettings.cs

View workflow job for this annotation

GitHub Actions / call-starter-workflow / call-dotnet-build-and-release-workflow / dotnet-build-and-release

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 76 in RemoteFile/ApplicationSettings.cs

View workflow job for this annotation

GitHub Actions / call-starter-workflow / call-dotnet-build-and-release-workflow / dotnet-build-and-release

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 76 in RemoteFile/ApplicationSettings.cs

View workflow job for this annotation

GitHub Actions / call-starter-workflow / call-dotnet-build-and-release-workflow / dotnet-build-and-release

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 76 in RemoteFile/ApplicationSettings.cs

View workflow job for this annotation

GitHub Actions / call-starter-workflow / call-dotnet-build-and-release-workflow / dotnet-build-and-release

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 76 in RemoteFile/ApplicationSettings.cs

View workflow job for this annotation

GitHub Actions / call-starter-workflow / call-dotnet-build-and-release-workflow / dotnet-build-and-release

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 76 in RemoteFile/ApplicationSettings.cs

View workflow job for this annotation

GitHub Actions / call-starter-workflow / call-dotnet-build-and-release-workflow / dotnet-build-and-release

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 76 in RemoteFile/ApplicationSettings.cs

View workflow job for this annotation

GitHub Actions / call-starter-workflow / call-dotnet-build-and-release-workflow / dotnet-build-and-release

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 76 in RemoteFile/ApplicationSettings.cs

View workflow job for this annotation

GitHub Actions / call-starter-workflow / call-dotnet-build-and-release-workflow / dotnet-build-and-release

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

if (!PropertyUtilities.TryEnumParse(protocolValue, out bool isFlagCombination, out FileTransferProtocolEnum protocol))
throw new RemoteFileException($"Invalid optional config.json FileTransferProtocol option of {protocolValue}. If present, must be one of these values: {protocolNames}.");
Expand Down
2 changes: 1 addition & 1 deletion RemoteFile/Discovery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public JobResult ProcessJob(DiscoveryJobConfiguration config, SubmitDiscoveryUpd
string userPassword = PAMUtilities.ResolvePAMField(_resolver, logger, "Server Password", config.ServerPassword);

certificateStore = new RemoteCertificateStore(config.ClientMachine, userName, userPassword, directoriesToSearch[0].Substring(0, 1) == "/" ? RemoteCertificateStore.ServerTypeEnum.Linux : RemoteCertificateStore.ServerTypeEnum.Windows, ApplicationSettings.SSHPort);
certificateStore.Initialize(ApplicationSettings.DefaultSudoImpersonatedUser);
certificateStore.Initialize(ApplicationSettings.DefaultSudoImpersonatedUser, true);

if (directoriesToSearch.Length == 0)
throw new RemoteFileException("Blank or missing search directories for Discovery.");
Expand Down
2 changes: 1 addition & 1 deletion RemoteFile/InventoryBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public JobResult ProcessJob(InventoryJobConfiguration config, SubmitInventoryUpd
SetJobProperties(config, config.CertificateStoreDetails, logger);

certificateStore = new RemoteCertificateStore(config.CertificateStoreDetails.ClientMachine, UserName, UserPassword, config.CertificateStoreDetails.StorePath, StorePassword, FileTransferProtocol, SSHPort, IncludePortInSPN);
certificateStore.Initialize(SudoImpersonatedUser);
certificateStore.Initialize(SudoImpersonatedUser, UseShellCommands);
certificateStore.LoadCertificateStore(certificateStoreSerializer, true);

List<X509Certificate2Collection> collections = certificateStore.GetCertificateChains();
Expand Down
2 changes: 1 addition & 1 deletion RemoteFile/ManagementBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public JobResult ProcessJob(ManagementJobConfiguration config)
SetJobProperties(config, config.CertificateStoreDetails, logger);

certificateStore = new RemoteCertificateStore(config.CertificateStoreDetails.ClientMachine, UserName, UserPassword, config.CertificateStoreDetails.StorePath, StorePassword, FileTransferProtocol, SSHPort, IncludePortInSPN);
certificateStore.Initialize(SudoImpersonatedUser);
certificateStore.Initialize(SudoImpersonatedUser, UseShellCommands);

PathFile storePathFile = RemoteCertificateStore.SplitStorePathFile(config.CertificateStoreDetails.StorePath);

Expand Down
2 changes: 1 addition & 1 deletion RemoteFile/ReenrollmentBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public JobResult ProcessJobToDo(ReenrollmentJobConfiguration config, SubmitReenr
ApplicationSettings.FileTransferProtocolEnum fileTransferProtocol = ApplicationSettings.FileTransferProtocol;

certificateStore = new RemoteCertificateStore(config.CertificateStoreDetails.ClientMachine, UserName, UserPassword, config.CertificateStoreDetails.StorePath, StorePassword, fileTransferProtocol, SSHPort, IncludePortInSPN);
certificateStore.Initialize(SudoImpersonatedUser);
certificateStore.Initialize(SudoImpersonatedUser, UseShellCommands);

PathFile storePathFile = RemoteCertificateStore.SplitStorePathFile(config.CertificateStoreDetails.StorePath);

Expand Down
4 changes: 2 additions & 2 deletions RemoteFile/RemoteCertificateStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -453,14 +453,14 @@ internal string GenerateCSROnDevice(string subjectText, SupportedKeyTypeEnum key
return csr;
}

internal void Initialize(string sudoImpersonatedUser)
internal void Initialize(string sudoImpersonatedUser, bool useShellCommands)
{
logger.MethodEntry(LogLevel.Debug);

bool treatAsLocal = Server.ToLower().EndsWith(LOCAL_MACHINE_SUFFIX);

if (ServerType == ServerTypeEnum.Linux || RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
RemoteHandler = treatAsLocal ? new LinuxLocalHandler() as IRemoteHandler : new SSHHandler(Server, ServerId, ServerPassword, ServerType == ServerTypeEnum.Linux, FileTransferProtocol, SSHPort, sudoImpersonatedUser) as IRemoteHandler;
RemoteHandler = treatAsLocal ? new LinuxLocalHandler() as IRemoteHandler : new SSHHandler(Server, ServerId, ServerPassword, ServerType == ServerTypeEnum.Linux, FileTransferProtocol, SSHPort, sudoImpersonatedUser, useShellCommands) as IRemoteHandler;
else
RemoteHandler = new WinRMHandler(Server, ServerId, ServerPassword, treatAsLocal, IncludePortInSPN);

Expand Down
7 changes: 6 additions & 1 deletion RemoteFile/RemoteFileJobTypeBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public abstract class RemoteFileJobTypeBase
internal bool IncludePortInSPN { get; set; }
internal ApplicationSettings.FileTransferProtocolEnum FileTransferProtocol { get; set; }
internal bool CreateCSROnDevice { get; set; }
internal bool UseShellCommands { get; set; }
internal string KeyType { get; set; }
internal int KeySize { get; set; }
internal string SubjectText { get; set; }
Expand Down Expand Up @@ -57,7 +58,7 @@ internal void SetJobProperties(JobConfiguration config, CertificateStore certifi
ApplicationSettings.DefaultSudoImpersonatedUser :
properties.SudoImpersonatedUser.Value;

SSHPort = properties.SSHPort == null || string.IsNullOrEmpty(properties.SSHPort.Value) || !int.TryParse(properties.SSHPort.Value, out int notUsed) ?
SSHPort = properties.SSHPort == null || string.IsNullOrEmpty(properties.SSHPort.Value) || !int.TryParse(properties.SSHPort.Value, out int _) ?
ApplicationSettings.SSHPort :
properties.SSHPort;

Expand All @@ -73,6 +74,10 @@ internal void SetJobProperties(JobConfiguration config, CertificateStore certifi
ApplicationSettings.CreateCSROnDevice :
Convert.ToBoolean(properties.CreateCSROnDevice.Value);

UseShellCommands = properties.UseShellCommands == null || string.IsNullOrEmpty(properties.UseShellCommands.Value) ?
ApplicationSettings.UseShellCommands :
properties.UseShellCommands;

FileTransferProtocol = ApplicationSettings.FileTransferProtocol;
if (properties.FileTransferProtocol != null && !string.IsNullOrEmpty(properties.FileTransferProtocol.Value))
{
Expand Down
78 changes: 49 additions & 29 deletions RemoteFile/RemoteHandlers/SSHHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,20 @@ class SSHHandler : BaseRemoteHandler
private string SudoImpersonatedUser { get; set; }
private ApplicationSettings.FileTransferProtocolEnum FileTransferProtocol { get; set; }
private bool IsStoreServerLinux { get; set; }
private bool UseShellCommands { 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, ApplicationSettings.FileTransferProtocolEnum fileTransferProtocol, int sshPort, string sudoImpersonatedUser)
internal SSHHandler(string server, string serverLogin, string serverPassword, bool isStoreServerLinux, ApplicationSettings.FileTransferProtocolEnum fileTransferProtocol, int sshPort, string sudoImpersonatedUser, bool useShellCommands)
{
_logger.MethodEntry(LogLevel.Debug);

Server = server;
SudoImpersonatedUser = sudoImpersonatedUser;
FileTransferProtocol = fileTransferProtocol;
IsStoreServerLinux = isStoreServerLinux;
UseShellCommands = useShellCommands;
UserId = serverLogin;
Password = serverPassword;

Expand Down Expand Up @@ -80,7 +82,8 @@ internal SSHHandler(string server, string serverLogin, string serverPassword, bo
sshClient.Connect();

//method call below necessary to check edge condition where password for user id has expired. SCP (and possibly SFTP) download hangs in that scenario
CheckConnection();
if (useShellCommands)
CheckConnection();
}
catch (Exception ex)
{
Expand Down Expand Up @@ -368,13 +371,20 @@ public override void CreateEmptyStoreFile(string path, string linuxFilePermissio
if (IsStoreServerLinux)
{
string pathOnly = string.Empty;
SplitStorePathFile(path, out pathOnly, out _);
string fileName = string.Empty;
SplitStorePathFile(path, out pathOnly, out fileName);

linuxFilePermissions = string.IsNullOrEmpty(linuxFilePermissions) ? GetFolderPermissions(pathOnly) : linuxFilePermissions;
linuxFileOwner = string.IsNullOrEmpty(linuxFileOwner) ? GetFolderOwner(pathOnly) : linuxFileOwner;
if (UseShellCommands)
{
linuxFilePermissions = string.IsNullOrEmpty(linuxFilePermissions) ? GetFolderPermissions(pathOnly) : linuxFilePermissions;
linuxFileOwner = string.IsNullOrEmpty(linuxFileOwner) ? GetFolderOwner(pathOnly) : linuxFileOwner;

AreLinuxPermissionsValid(linuxFilePermissions);

AreLinuxPermissionsValid(linuxFilePermissions);
RunCommand($"install -m {linuxFilePermissions} -o {linuxFileOwner} {linuxFileGroup} /dev/null {path}", null, ApplicationSettings.UseSudo, null);
RunCommand($"install -m {linuxFilePermissions} -o {linuxFileOwner} {linuxFileGroup} /dev/null {path}", null, ApplicationSettings.UseSudo, null);
}
else
UploadCertificateFile(pathOnly, fileName, Array.Empty<byte>());
}
else
RunCommand($@"Out-File -FilePath ""{path}""", null, false, null);
Expand All @@ -386,28 +396,38 @@ public override bool DoesFileExist(string path)
{
_logger.MethodEntry(LogLevel.Debug);
_logger.LogDebug($"DoesFileExist: {path}");

string rtn = RunCommand($"ls {path} >> /dev/null 2>&1 && echo True || echo False", null, ApplicationSettings.UseSudo, null);
return Convert.ToBoolean(rtn);

//using (SftpClient client = new SftpClient(Connection))
//{
// try
// {
// client.Connect();
// string existsPath = FormatFTPPath(path, !IsStoreServerLinux);
// bool exists = client.Exists(existsPath);
// _logger.LogDebug(existsPath);

// _logger.MethodExit(LogLevel.Debug);

// return exists;
// }
// finally
// {
// client.Disconnect();
// }
//}

bool exists = false;

if (UseShellCommands)
{
exists = Convert.ToBoolean(RunCommand($"ls {path} >> /dev/null 2>&1 && echo True || echo False", null, ApplicationSettings.UseSudo, null));
}
else
{
using (SftpClient client = new SftpClient(Connection))
{
try
{
client.Connect();
string existsPath = FormatFTPPath(path, !IsStoreServerLinux);
exists = client.Exists(existsPath);
_logger.LogDebug(existsPath);
}
catch (Exception ex)
{
_logger.LogError(RemoteFileException.FlattenExceptionMessages(ex, "Error checking existence of file {path} using SFTP"));
throw;
}
finally
{
_logger.MethodExit(LogLevel.Debug);
client.Disconnect();
}
}
}

return exists;
}

public override void RemoveCertificateFile(string path, string fileName)
Expand Down
29 changes: 28 additions & 1 deletion docsource/content.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ The Remote File Orchestrator Extension uses a JSON configuration file. It is loc
"FileTransferProtocol": "SCP",
"DefaultLinuxPermissionsOnStoreCreation": "600",
"DefaultOwnerOnStoreCreation": "",
"SSHPort": ""
"SSHPort": "",
"UseShellCommands": "Y"
}
```

Expand All @@ -134,6 +135,7 @@ The Remote File Orchestrator Extension uses a JSON configuration file. It is loc
| `DefaultLinuxPermissionsOnStoreCreation` | `600` | Any 3-digit value from 000-777 | Linux file permissions set on new certificate stores. If blank, permissions from the parent folder will be used. Only applicable for Linux hosted certificate stores. |
| `DefaultOwnerOnStoreCreation` | | Any valid user id | Sets the owner for newly created certificate stores. Can include group with format `ownerId:groupId`. If blank, the owner of the parent folder will be used. Only applicable for Linux hosted certificate stores. |
| `SSHPort` | | Any valid integer representing a port | The port that SSH is listening on. Default is 22. Only applicable for Linux hosted certificate stores. |
| `UseShellCommands` | `Y` | `Y/N` | Recommended to be set to the default value of 'Y'. For a detailed explanation of this setting, please refer to [Use Shell Commands Setting](#use-shell-commands-setting) |

## Discovery

Expand Down Expand Up @@ -182,6 +184,31 @@ For agent mode (accessing stores on the same server where Universal Orchestrator
- `Store Type` + `Client Machine` + `Store Path` must be unique in Keyfactor Command
- Best practice: Use the full DNS or IP Address to the left of the `|` character


## Use Shell Commands Setting

The Use Shell Commands Setting (orchestrator level in config.json and per store override of this value as a custom field value)
determines whether or not Linux shell commands will be used when managing certificate stores on Linux-based servers.
This is useful for environments where shell access is limited or even not allowed. In those scenarios setting this value to 'N'
will substitute SFTP commands for certain specific Linux shell commands. The following restrictions will be in place when
using RemoteFile in this mode:
1. The config.json option SeparateUploadFilePath must NOT be used (option missing from the config.json file or set to empty) for shell
commands to be suppressed for all use cases.
2. The config.json and custom field options DefaultLinuxPermissionsOnStoreCreation, DefaultOwnerOnStoreCreation,
LinuxFilePermissionsOnStoreCreation, and LinuxFileOwnerOnStoreCreation are not supported and will be ignored. As a result, file
permissions and ownership when creating certificate stores will be based on the user assigned to the Command certificate store and
other Linux environmental settings.
3. Discovery jobs are excluded and will still use the `find` shell command
4. A rare issue exists where the user id assigned to a certificate store has an expired password causing the orchestrator to hang
when attempting an SFTP/SCP connection. A modification was added to RemoteFile to check for this condition. Running RemoteFile
with Use Shell Commands = N will cause this validation check to NOT occur.
5. Both RFORA and RFKDB use proprietary CLI commands in order to manage their respective certificate stores. These commands
will still be executed when Use Shell Commands is set to Y.
6. If executing in local mode ('|LocalMachine' at the end of your client machine name for your certificate store), Use Shell
Commands = 'N' will have no effect. Shell commands will continue to be used because there will be no SSH connection
available from which to execute SFTP commands.


## Developer Notes

The Remote File Orchestrator Extension is designed to be highly extensible, enabling its use with various file-based
Expand Down
Binary file modified docsource/images/RFDER-advanced-store-type-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docsource/images/RFDER-basic-store-type-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docsource/images/RFDER-custom-fields-store-type-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docsource/images/RFJKS-advanced-store-type-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docsource/images/RFJKS-basic-store-type-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docsource/images/RFJKS-custom-fields-store-type-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docsource/images/RFKDB-advanced-store-type-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docsource/images/RFKDB-basic-store-type-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docsource/images/RFKDB-custom-fields-store-type-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docsource/images/RFORA-advanced-store-type-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docsource/images/RFORA-basic-store-type-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docsource/images/RFPEM-advanced-store-type-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docsource/images/RFPEM-basic-store-type-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docsource/images/RFPEM-custom-fields-store-type-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docsource/images/RFPkcs12-advanced-store-type-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docsource/images/RFPkcs12-basic-store-type-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docsource/images/RFPkcs12-custom-fields-store-type-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading