Skip to content

Commit

Permalink
Merge pull request #3 from Keyfactor/release-1.0
Browse files Browse the repository at this point in the history
Merge 1.0.0 to main
  • Loading branch information
fiddlermikey authored Jan 21, 2025
2 parents fac28ff + 9310b44 commit fc0f9f8
Show file tree
Hide file tree
Showing 27 changed files with 1,098 additions and 500 deletions.
27 changes: 27 additions & 0 deletions .github/workflows/keyfactor-merge-store-types.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Keyfactor Merge Cert Store Types
on: [workflow_dispatch]

jobs:
get-manifest-properties:
runs-on: windows-latest
outputs:
update_catalog: ${{ steps.read-json.outputs.update_catalog }}
integration_type: ${{ steps.read-json.outputs.integration_type }}
steps:
- uses: actions/checkout@v3
- name: Store json
id: read-json
shell: pwsh
run: |
$json = Get-Content integration-manifest.json | ConvertFrom-Json
$myvar = $json.update_catalog
echo "update_catalog=$myvar" | Out-File -FilePath $Env:GITHUB_OUTPUT -Encoding utf8 -Append
$myvar = $json.integration_type
echo "integration_type=$myvar" | Out-File -FilePath $Env:GITHUB_OUTPUT -Encoding utf8 -Append
call-update-store-types-workflow:
needs: get-manifest-properties
if: needs.get-manifest-properties.outputs.integration_type == 'orchestrator' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
uses: Keyfactor/actions/.github/workflows/update-store-types.yml@main
secrets:
token: ${{ secrets.UPDATE_STORE_TYPES }}
20 changes: 20 additions & 0 deletions .github/workflows/keyfactor-starter-workflow.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Keyfactor Bootstrap Workflow

on:
workflow_dispatch:
pull_request:
types: [opened, closed, synchronize, edited, reopened]
push:
create:
branches:
- 'release-*.*'

jobs:
call-starter-workflow:
uses: keyfactor/actions/.github/workflows/[email protected]
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 }}
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
v1.0.0
- Initial Version
2 changes: 1 addition & 1 deletion SampleOrchestratorExtension.sln → GCPSecretManager.sln
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31702.278
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleOrchestratorExtension", "SampleOrchestratorExtension\SampleOrchestratorExtension.csproj", "{ECFD4531-6959-431C-8D5A-8CD62301A82A}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GCPSecretManagereOrchestratorExtension", "GCPSecretManager\GCPSecretManager.csproj", "{ECFD4531-6959-431C-8D5A-8CD62301A82A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down
24 changes: 24 additions & 0 deletions GCPSecretManager/CertificateFormatter/BaseCertificateFormatter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Keyfactor.Logging;
using Microsoft.Extensions.Logging;

namespace Keyfactor.Extensions.Orchestrator.GCPSecretManager

{
abstract class BaseCertificateFormatter : ICertificateFormatter
{
internal ILogger Logger { get; set; }

internal BaseCertificateFormatter()
{
Logger = LogHandler.GetClassLogger(this.GetType());
}

public abstract bool HasPrivateKey(string entry);

public abstract bool IsValid(string entry);

public abstract string[] ConvertSecretToCertificateChain(string entry);

public abstract string ConvertCertificateEntryToSecret(string certificateContents, string privateKeyPassword, bool includeChain, string newPassword);
}
}
20 changes: 20 additions & 0 deletions GCPSecretManager/CertificateFormatter/ICertificateFormatter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Keyfactor.Extensions.Orchestrator.GCPSecretManager

{
interface ICertificateFormatter
{
bool HasPrivateKey(string entry);

bool IsValid(string entry);

string[] ConvertSecretToCertificateChain(string entry);

string ConvertCertificateEntryToSecret(string certificateContents, string privateKeyPassword, bool includeChain, string newPassword);
}
}
121 changes: 121 additions & 0 deletions GCPSecretManager/CertificateFormatter/PEMCertificateFormatter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

using Microsoft.Extensions.Logging;

using Keyfactor.Logging;
using Keyfactor.PKI.PEM;
using Keyfactor.PKI.PrivateKeys;
using Keyfactor.PKI.X509;

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Pkcs;

namespace Keyfactor.Extensions.Orchestrator.GCPSecretManager

{
class PEMCertificateFormatter : BaseCertificateFormatter
{
private string BEGIN_DELIMITER = "-----BEGIN CERTIFICATE-----";
private string END_DELIMITER = "-----END CERTIFICATE-----";
private string[] PRIVATE_KEY_DELIMITERS = new string[] { "-----BEGIN PRIVATE KEY-----", "-----BEGIN ENCRYPTED PRIVATE KEY-----", "-----BEGIN RSA PRIVATE KEY-----" };

public override bool HasPrivateKey(string entry)
{
Logger.MethodEntry(LogLevel.Debug);

bool rtnValue = false;

foreach (string privateKeyDelimiter in PRIVATE_KEY_DELIMITERS)
{
if (entry.Contains(privateKeyDelimiter, StringComparison.OrdinalIgnoreCase))
{
rtnValue = true;
break;
}
}

Logger.MethodExit(LogLevel.Debug);

return rtnValue;
}

public override bool IsValid(string entry)
{
Logger.MethodEntry(LogLevel.Debug);

Logger.MethodExit(LogLevel.Debug);

return entry.Contains(BEGIN_DELIMITER, StringComparison.OrdinalIgnoreCase) && entry.Contains(END_DELIMITER, StringComparison.OrdinalIgnoreCase);
}

public override string[] ConvertSecretToCertificateChain(string entry)
{
Logger.MethodEntry(LogLevel.Debug);

entry = entry.Replace(System.Environment.NewLine, string.Empty);
List<string> rtnCertificates = new List<String>();
int currStart = 0;
int currEnd = 0;

do
{
currStart = entry.IndexOf(BEGIN_DELIMITER, currEnd) + BEGIN_DELIMITER.Length;
currEnd = entry.IndexOf(END_DELIMITER, currStart);
rtnCertificates.Add(entry.Substring(currStart, currEnd - currStart));
currEnd++;
}
while (entry.IndexOf(END_DELIMITER, currEnd) > -1);

Logger.MethodExit(LogLevel.Debug);

return rtnCertificates.ToArray();
}

public override string ConvertCertificateEntryToSecret(string certificateContents, string privateKeyPassword, bool includeChain, string newPassword)
{
Logger.MethodEntry(LogLevel.Debug);

if (string.IsNullOrEmpty(privateKeyPassword))
return PemUtilities.DERToPEM(Convert.FromBase64String(certificateContents), PemUtilities.PemObjectType.Certificate);

Pkcs12StoreBuilder builder = new Pkcs12StoreBuilder();
Pkcs12Store pkcs12Store = builder.Build();
using (MemoryStream ms = new MemoryStream(Convert.FromBase64String(certificateContents)))
{
pkcs12Store.Load(ms, privateKeyPassword.ToCharArray());
}

string alias = pkcs12Store.Aliases.First();

X509CertificateEntry[] certChainEntries = pkcs12Store.GetCertificateChain(alias);
CertificateConverter certConverter = CertificateConverterFactory.FromBouncyCastleCertificate(certChainEntries[0].Certificate);

AsymmetricKeyParameter privateKey = pkcs12Store.GetKey(alias).Key;
AsymmetricKeyParameter publicKey = certChainEntries[0].Certificate.GetPublicKey();

PrivateKeyConverter keyConverter = PrivateKeyConverterFactory.FromBCKeyPair(privateKey, publicKey, false);

byte[] privateKeyBytes = string.IsNullOrEmpty(newPassword) ? keyConverter.ToPkcs8BlobUnencrypted() : keyConverter.ToPkcs8Blob(newPassword);
string keyString = PemUtilities.DERToPEM(privateKeyBytes, string.IsNullOrEmpty(newPassword) ? PemUtilities.PemObjectType.PrivateKey : PemUtilities.PemObjectType.EncryptedPrivateKey);

string pemString = certConverter.ToPEM(true);
pemString += keyString;

if (includeChain)
{
for (int i = 1; i < certChainEntries.Length; i++)
{
CertificateConverter chainConverter = CertificateConverterFactory.FromBouncyCastleCertificate(certChainEntries[i].Certificate);
pemString += chainConverter.ToPEM(true);
}
}

Logger.MethodExit(LogLevel.Debug);

return pemString;
}
}
}
29 changes: 29 additions & 0 deletions GCPSecretManager/ExceptionHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2021 Keyfactor
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
// and limitations under the License.

using System;

namespace Keyfactor.Extensions.Orchestrator.GCPSecretManager
{
class GCPException : ApplicationException
{
public GCPException(string message) : base(message)
{ }

public GCPException(string message, Exception ex) : base(message, ex)
{ }

public static string FlattenExceptionMessages(Exception ex, string message)
{
message += ex.Message + Environment.NewLine;
if (ex.InnerException != null)
message = FlattenExceptionMessages(ex.InnerException, message);

return message;
}
}
}
Loading

0 comments on commit fc0f9f8

Please sign in to comment.