Skip to content

Commit

Permalink
[CLI] add --issuer option for exporting PFX (#143)
Browse files Browse the repository at this point in the history
  • Loading branch information
fszlin authored Jul 13, 2018
1 parent 61e9133 commit 283c995
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 3 deletions.
5 changes: 5 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Changelog
All notable changes to this project will be documented in this file.

## [Unreleased]
### Added
- [CLI] Add `--issuer` option to `cert pfx` command ([#142][i142])

## [2.3.0] - 2018-06-15
### Added
- Support `tls-alpn-01` challenge ([#125][i125])
Expand Down Expand Up @@ -99,3 +103,4 @@ All notable changes to this project will be documented in this file.
[i112]: https://github.com/fszlin/certes/issues/112
[i125]: https://github.com/fszlin/certes/issues/125
[i109]: https://github.com/fszlin/certes/issues/109
[i142]: https://github.com/fszlin/certes/issues/142
2 changes: 1 addition & 1 deletion docs/docstrap
Submodule docstrap updated from 4536e7 to 74b223
14 changes: 13 additions & 1 deletion src/Certes.Cli/Commands/CertificatePfxCommand.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.CommandLine;
using System.Globalization;
using System.Text;
using System.Threading.Tasks;
using Certes.Cli.Settings;
using NLog;
Expand All @@ -13,6 +14,7 @@ internal class CertificatePfxCommand : CertificateCommand, ICliCommand
private const string PasswordParam = "password";
private const string PrivateKeyOption = "private-key";
private const string OutOption = "out";
private const string IssuerOption = "issuer";
private static readonly ILogger logger = LogManager.GetLogger(nameof(CertificatePfxCommand));

private readonly IEnvironmentVariables environment;
Expand All @@ -36,6 +38,7 @@ public ArgumentCommand<string> Define(ArgumentSyntax syntax)
.DefineKeyOption()
.DefineOption(OutOption, help: Strings.HelpCertificateOut)
.DefineOption(PrivateKeyOption, help: Strings.HelpPrivateKey)
.DefineOption(IssuerOption, help: Strings.HelpCertificateIssuer)
.DefineUriParameter(OrderIdParam, help: Strings.HelpOrderId)
.DefineParameter(PasswordParam, help: Strings.HelpPfxPassword);

Expand All @@ -46,11 +49,20 @@ public async Task<object> Execute(ArgumentSyntax syntax)
{
var keyPath = syntax.GetParameter<string>(PrivateKeyOption, true);
var pwd = syntax.GetParameter<string>(PasswordParam, true);
var issuer = syntax.GetParameter<string>(IssuerOption);
var (location, cert) = await DownloadCertificate(syntax);

var pfxName = string.Format(CultureInfo.InvariantCulture, "[certes] {0:yyyyMMddhhmmss}", DateTime.UtcNow);
var privKey = await syntax.ReadKey(PrivateKeyOption, "CERTES_CERT_KEY", File, environment, true);
var pfx = cert.ToPfx(privKey).Build(pfxName, pwd);

var pfxBuilder = cert.ToPfx(privKey);
if (!string.IsNullOrWhiteSpace(issuer))
{
var issuerPem = await File.ReadAllText(issuer);
pfxBuilder.AddIssuers(Encoding.UTF8.GetBytes(issuerPem));
}

var pfx = pfxBuilder.Build(pfxName, pwd);

var outPath = syntax.GetOption<string>(OutOption);
if (string.IsNullOrWhiteSpace(outPath))
Expand Down
9 changes: 9 additions & 0 deletions src/Certes.Cli/Strings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/Certes.Cli/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -267,4 +267,7 @@
<data name="HelpCommandAzureSet" xml:space="preserve">
<value>Configure default credentials for Microsoft Azure.</value>
</data>
<data name="HelpCertificateIssuer" xml:space="preserve">
<value>Additional certificates for building the certificate chain.</value>
</data>
</root>
16 changes: 15 additions & 1 deletion test/Certes.Tests/Cli/Commands/CertificatePfxCommandTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.CommandLine;
using System.Linq;
using System.Threading.Tasks;
using Certes.Acme;
using Certes.Acme.Resource;
Expand Down Expand Up @@ -75,16 +76,29 @@ public async Task CanProcessCommand()
JsonConvert.SerializeObject(ret));

fileMock.Verify(m => m.WriteAllBytes(outPath, It.IsAny<byte[]>()), Times.Once);
fileMock.ResetCalls();

// Export PFX with external issuers
var leafCert = certChain.Certificate.ToPem();
orderMock.Setup(m => m.Download()).ReturnsAsync(new CertificateChain(leafCert));

var issuersPem = string.Join(Environment.NewLine, certChain.Issuers.Select(i => i.ToPem()));
fileMock.Setup(m => m.ReadAllText("./issuers.pem")).ReturnsAsync(issuersPem);

syntax = DefineCommand($"pfx {orderLoc} --private-key {privateKeyPath} abcd1234 --out {outPath} --issuer ./issuers.pem");
ret = await cmd.Execute(syntax);
fileMock.Verify(m => m.WriteAllBytes(outPath, It.IsAny<byte[]>()), Times.Once);
}

[Fact]
public void CanDefineCommand()
{
var args = $"pfx http://acme.com/o/1 --private-key ./my-key.pem abcd1234 --server {LetsEncryptStagingV2}";
var args = $"pfx http://acme.com/o/1 --private-key ./my-key.pem abcd1234 --server {LetsEncryptStagingV2} --issuer ./root-cert.pem";
var syntax = DefineCommand(args);

Assert.Equal("pfx", syntax.ActiveCommand.Value);
ValidateOption(syntax, "server", LetsEncryptStagingV2);
ValidateOption(syntax, "issuer", "./root-cert.pem");
ValidateParameter(syntax, "order-id", new Uri("http://acme.com/o/1"));
ValidateParameter(syntax, "private-key", "./my-key.pem");
ValidateParameter(syntax, "password", "abcd1234");
Expand Down

0 comments on commit 283c995

Please sign in to comment.