Skip to content

Commit 3ebe0a9

Browse files
maybe-hello-worldiSazonov
authored andcommitted
Add Password parameter to Get-PfxCertificate cmdlet (#6113)
Add Password parameter to Get-PfxCertificate cmdlet to allow automatization instead of prompting for password every time.
1 parent 26b7be7 commit 3ebe0a9

3 files changed

Lines changed: 71 additions & 48 deletions

File tree

src/Microsoft.PowerShell.Security/security/CertificateCommands.cs

Lines changed: 37 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,18 @@ public string[] LiteralPath
6262
}
6363
private bool _isLiteralPath = false;
6464

65+
/// <summary>
66+
/// Gets or sets the password for unlocking the certificate.
67+
/// </summary>
68+
[Parameter(Mandatory = false)]
69+
public SecureString Password { get; set; }
70+
71+
/// <summary>
72+
/// Do not prompt for password if not given.
73+
/// </summary>
74+
[Parameter(Mandatory = false)]
75+
public SwitchParameter NoPromptForPassword { get; set; }
76+
6577
//
6678
// list of files that were not found
6779
//
@@ -126,47 +138,35 @@ protected override void ProcessRecord()
126138
}
127139
else
128140
{
141+
if (Password == null && !NoPromptForPassword.IsPresent)
142+
{
143+
try
144+
{
145+
cert = GetCertFromPfxFile(resolvedProviderPath, null);
146+
WriteObject(cert);
147+
continue;
148+
}
149+
catch (CryptographicException)
150+
{
151+
Password = SecurityUtils.PromptForSecureString(
152+
Host.UI,
153+
CertificateCommands.GetPfxCertPasswordPrompt);
154+
}
155+
}
156+
129157
try
130158
{
131-
cert = GetCertFromPfxFile(resolvedProviderPath);
159+
cert = GetCertFromPfxFile(resolvedProviderPath, Password);
132160
}
133-
catch (CryptographicException)
161+
catch (CryptographicException e)
134162
{
135-
//
136-
// CryptographicException is thrown when any error
137-
// occurs inside the crypto class library. It has a
138-
// protected member HResult that indicates the exact
139-
// error but it is not available outside the class.
140-
// Thus we have to assume that the above exception
141-
// was thrown because the pfx file is password
142-
// protected.
143-
//
144-
SecureString password = null;
145-
146-
string prompt = null;
147-
prompt = CertificateCommands.GetPfxCertPasswordPrompt;
148-
149-
password = SecurityUtils.PromptForSecureString(Host.UI, prompt);
150-
try
151-
{
152-
cert = GetCertFromPfxFile(resolvedProviderPath,
153-
password);
154-
}
155-
catch (CryptographicException e)
156-
{
157-
//
158-
// since we cannot really figure out the
159-
// meaning of a given CryptographicException
160-
// we have to use NotSpecified category here
161-
//
162-
ErrorRecord er =
163-
new ErrorRecord(e,
164-
"GetPfxCertificateUnknownCryptoError",
165-
ErrorCategory.NotSpecified,
166-
null);
167-
WriteError(er);
168-
continue;
169-
}
163+
ErrorRecord er =
164+
new ErrorRecord(e,
165+
"GetPfxCertificateUnknownCryptoError",
166+
ErrorCategory.NotSpecified,
167+
null);
168+
WriteError(er);
169+
continue;
170170
}
171171

172172
WriteObject(cert);
@@ -206,12 +206,6 @@ protected override void ProcessRecord()
206206
}
207207
}
208208

209-
private static X509Certificate2 GetCertFromPfxFile(string path)
210-
{
211-
X509Certificate2 cert = new X509Certificate2(path);
212-
return cert;
213-
}
214-
215209
private static X509Certificate2 GetCertFromPfxFile(string path, SecureString password)
216210
{
217211
var cert = new X509Certificate2(path, password, X509KeyStorageFlags.DefaultKeySet);

test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33
Import-Module (Join-Path -Path $PSScriptRoot 'certificateCommon.psm1') -Force
44

55
Describe "CmsMessage cmdlets and Get-PfxCertificate basic tests" -Tags "CI" {
6-
6+
77
BeforeAll {
88
$certLocation = New-GoodCertificate
99
$certLocation | Should Not BeNullOrEmpty | Out-Null
10+
11+
$protectedCertLocation = New-ProtectedCertificate
12+
$protectedCertLocation | Should Not BeNullOrEmpty | Out-Null
1013
}
1114

1215
It "Verify Get-PfxCertificate -FilePath" {
@@ -24,6 +27,17 @@ Describe "CmsMessage cmdlets and Get-PfxCertificate basic tests" -Tags "CI" {
2427
$cert.Subject | Should Be "CN=MyDataEnciphermentCert"
2528
}
2629

30+
It "Verify Get-PfxCertificate right password" {
31+
$pass = ConvertTo-SecureString "password" -AsPlainText -Force
32+
$cert = Get-PfxCertificate $protectedCertLocation -Password $pass
33+
$cert.Subject | Should Be "CN=localhost"
34+
}
35+
36+
It "Verify Get-PfxCertificate wrong password" {
37+
$pass = ConvertTo-SecureString "wrongpass" -AsPlainText -Force
38+
$e = { Get-PfxCertificate $protectedCertLocation -Password $pass -ErrorAction Stop } | ShouldBeErrorId "GetPfxCertificateUnknownCryptoError,Microsoft.PowerShell.Commands.GetPfxCertificateCommand"
39+
}
40+
2741
It "Verify CMS message recipient resolution by path" -Skip:(!$IsWindows) {
2842
$errors = $null
2943
$recipient = [System.Management.Automation.CmsMessageRecipient] $certLocation
@@ -72,9 +86,9 @@ Describe "CmsMessage cmdlets thorough tests" -Tags "Feature" {
7286
# Skip for non-Windows platforms
7387
$defaultParamValues = $PSdefaultParameterValues.Clone()
7488
$PSdefaultParameterValues = @{ "it:skip" = $true }
75-
}
89+
}
7690
}
77-
91+
7892
AfterAll {
7993
if($IsWindows)
8094
{
@@ -319,7 +333,7 @@ Describe "CmsMessage cmdlets thorough tests" -Tags "Feature" {
319333

320334
# Validate they all match the EKU
321335
$correctMatching = $foundCerts | Where-Object {
322-
($_.EnhancedKeyUsageList.Count -gt 0) -and
336+
($_.EnhancedKeyUsageList.Count -gt 0) -and
323337
($_.EnhancedKeyUsageList[0].ObjectId -eq '1.3.6.1.4.1.311.80.1')
324338
}
325339
# "All Document Encryption Cert should have had correct EKU"

test/powershell/Modules/Microsoft.PowerShell.Security/certificateCommon.psm1

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,21 @@ OksttXT1kXf+aez9EzDlsgQU4ck78h0WTy01zHLwSKNWK4wFFQM=
6868
return $certLocation
6969
}
7070

71+
Function New-ProtectedCertificate
72+
{
73+
<#
74+
.SYNOPSIS
75+
Return existing password-protected pfx certificate
76+
77+
.NOTES
78+
Password: "password"
79+
#>
80+
81+
$certLocation = ".\test\tools\Modules\WebListener\ServerCert.pfx"
82+
83+
return $certLocation
84+
}
85+
7186
Function New-BadCertificate
7287
{
7388
$codeSigningCert = "
@@ -166,4 +181,4 @@ function Remove-TestCertificates
166181
else {
167182
throw 'Not supported on non-windows platforms'
168183
}
169-
}
184+
}

0 commit comments

Comments
 (0)