X509Certificate2 构造函数使用 Powershell 因 Byte[] 失败

X509Certificate2 Constructor fails with Byte[] using Powershell

我希望我错过了一些明显的东西,因为我尝试了 3 种不同的方法来生成 PFX/PKCS12 字节数组,以便启动 X509Certificate2 class。

问题:代码抛出异常:

Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException: 'The specified network password is not correct'

目标:生成包含私钥的X509Certificate2,私钥通过以下代码与组织在开发中自签名证书的最佳实践:


public static X509Certificate2 GetSigningCertificate(byte[] rawBytes)
{
    X509Certificate2 certificate;
    try
    {
        certificate= new X509Certificate2(rawBytes);
    }
    catch (Exception ex)
    {
        throw new Exception(Errors.MalformedCertificate);
    }

    if (!certificate.HasPrivateKey)
    {
        throw new Exception(Errors.PrivateKeyIsMissing);
    }

    return certificate;
}

代码限制:由于 political/organization 政策,上面接受 byte[] 的代码不能由我直接修改,因为它由另一个人控制团队(所有者)。如果在 所有 之后可能的选项都被 耗尽 我将提交一份正式的请求文档来讨论有正当理由的代码更改。

平台:Windows10 企业 (1803)

编译目标:netstandard2 & .Net 4.7.1

自动化工具方法 1:使用 OpenSSL

openssl.exe rand -out C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration.rnd -base64 4096
openssl.exe genrsa -rand "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration.rnd" -passout pass:"RfTjWnZr4u7x!A%E" -out "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-private-key.pem" 2048
openssl.exe genrsa -rand "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration.rnd" -passout pass:"RfTjWnZr4u7x!A%E" -out "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-private-key-encrypted.pem" -des3 2048
openssl.exe rsa -in "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-private-key.pem" -pubout -out "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-privatekey-corresponding-public-key.pem"
openssl.exe rsa -in "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-private-key.pem" -RSAPublicKey_out -out "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-privatekey-corresponding-rsa-public-key.pem"
openssl.exe req -x509 -days 90 -passin pass:"RfTjWnZr4u7x!A%E" -key "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-private-key-encrypted.pem" -out "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-certificate.cer" -subj "/C=US/ST=CA/L=Newport Beach/O=AutoNow Inc/OU=Application Development/CN=*.autonow.com"
openssl.exe req -new -key "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-private-key.pem" -out "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-certificate-signature.csr" -subj "/C=US/ST=CA/L=Newport Beach/O=AutoNow Inc/OU=Application Development/CN=*.autonow.com"
openssl.exe pkcs12 -export  -aes256 -CSP "Microsoft Enhanced RSA and AES Cryptographic Provider" -name "" -out "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration.pfx" -passin pass:"RfTjWnZr4u7x!A%E" -inkey "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-private-key-encrypted.pem" -in "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-certificate.cer" -passout pass:"VkXp2s5v8x/A?D(G"
openssl.exe pkcs12 -out "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration.pem" -passin pass:"VkXp2s5v8x/A?D(G" -in "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration.pfx" -passout pass:"VkXp2s5v8x/A?D(G" -clcerts -aes256 -CSP "Microsoft Enhanced RSA and AES Cryptographic Provider"

自动化工具方法 2:使用 Powershell cmdlet

$VerbosePreference = "Continue"

$certStorePath = "Cert:\CurrentUser\My"

$friendlyName = "Customer Support Administration Tool SelfSigned Certificate"
$name = "*.autonow.com"
$dnsname = "services-dev.autonow.com, *.autonow.com, localhost"

$notBefore = $(Get-Date).Date.AddDays(-90)
$notAfter = $(Get-Date).Date.AddDays(90)

$pfxPassword = ConvertTo-SecureString -String "^adhd.Customer.Support.Administration.Tool.20190214" -Force -AsPlainText

$selfSignedCertificate = New-SelfSignedCertificate `
    -Subject $name `
    -DnsName $dnsname `
    -KeyAlgorithm RSA `
    -KeyLength 2048 `
    -NotBefore $notBefore `
    -NotAfter $notAfter `
    -CertStoreLocation $certStorePath `
    -FriendlyName $friendlyName `
    -HashAlgorithm SHA256 `
    -KeyUsage DigitalSignature, KeyEncipherment, DataEncipherment `
    -KeyExportPolicy Exportable `
    -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.1") `
      
$selfSignedCertificatePath = Join-Path -Path $certStorePath -ChildPath "$($selfSignedCertificate.Thumbprint)".ToUpper() 
Write-Debug $selfSignedCertificatePath

# Create temporary certificate path
$tmpPath = "C:\Vault\OpenSSL\Certificates\API\customer-support-administration"
If(!(test-path $tmpPath))
{
    $created = New-Item -ItemType Directory -Force -Path $tmpPath
}
Write-Debug $tmpPath

# Set certificate password here
$pfxFilePath = Join-Path -Path $tmpPath -ChildPath "customer-support-administration.pfx"

Write-Debug $pfxFilePath

$cerFilePath = Join-Path -Path $tmpPath -ChildPath "customer-support-administration.cer"
Write-Debug $cerFilePath

# Create pfx certificate
$exportedPfx = Export-PfxCertificate -Cert $selfSignedCertificatePath -FilePath $pfxFilePath -Password $pfxPassword -Force -CryptoAlgorithmOption AES256_SHA256
$exportedCer = Export-Certificate -Cert $selfSignedCertificatePath -FilePath $cerFilePath -Type CERT -Force

#
# Get Raw Bytes idea 1
#
[Byte[]]$pfxBytes = [System.IO.File]::ReadAllBytes($exportedPfx.FullName)
$pfx = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList (,$pfxBytes), $pfxPassword

If (-not $pfx.HasPrivateKey)
{
    throw [System.Exception]::new("The certificate is incompatible with the security requirements.")
}
# Read directly from the file for the raw bytes
$pfxBase64 = [Convert]::ToBase64String($pfxBytes)

# moment of truth instantiate the certificate using the security package code for idea 1
[Byte[]]$pfxBytes = [Convert]::FromBase64String($exportBase64)
$pfx = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList (,$pfxBytes),$pfxPassword

If (-not $pfx.HasPrivateKey)
{
    throw [System.Exception]::new("The rehydrated certificate is incompatible with the security requirements.")
}




#
# Get Raw Bytes idea 2
#
$pfxKeyFlags = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable -bor 
    [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet -bor 
    [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::UserKeySet

$pfx = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$pfx.Import($pfxBytes, $pfxPassword, $pfxKeyFlags)

If (-not $pfx.HasPrivateKey)
{
    throw [System.Exception]::new("The certificate is incompatible with the security requirements.")
}

$exportedBytes = $pfx.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Pfx, $pfxPassword)
$exportBase64 = [Convert]::ToBase64String($exportedBytes)

# test the instantiate 
[Byte[]]$newPfxBytes = [Convert]::FromBase64String($exportBase64)
$pfx = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList ($newPfxBytes,$pfxPassword)

If (-not $pfx.HasPrivateKey)
{
    throw [System.Exception]::new("The rehydrated certificate is incompatible with the security requirements.")
}

# moment of truth instantiate the certificate using the security package code 
[Byte[]]$newPfxBytes = [Convert]::FromBase64String($exportBase64)
$pfx = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList (,$newPfxBytes)

If (-not $pfx.HasPrivateKey)
{
    throw [System.Exception]::new("The rehydrated certificate is incompatible with the security requirements.")
}

最后结果还是抛出异常

New-Object : Exception calling ".ctor" with "1" argument(s): "The specified network password is not correct.
"
At line:2 char:8
+ $pfx = New-Object System.Security.Cryptography.X509Certificates.X509C ...
+        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidOperation: (:) [New-Object], MethodInvocationException
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand

想法#2 base64 的输出:

PS C:\WINDOWS\system32> $exportBase64
MIIKwAIBAzCCCnwGCSqGSIb3DQEHAaCCCm0EggppMIIKZTCCBfYGCSqGSIb3DQEHAaCCBecEggXjMIIF3zCCBdsGCyqGSIb3DQEMCgECoIIE9jCCBPIwHAYKKoZIhvcNAQwBAzAOBAgi31AW/5cI5gICB9A
EggTQVgPWXArFCY2eg2jv+hDLZsc+i3wEqw4Cy2CYgcj86WnRE0n/zVcNzi9lyH5jK1zpBfTpAnfTO4WNG8cdQ5qCtOy9TjkTyrGYrXywrGHgLYmHpsg43uMMWcihWO5+zek4YP3MQDtyuQT2+hCaviFwFu
TovlaLHjGlNcYAz7AlL/6sJ54EzTjo8zfKW08zaR1GsEeP9odYIlgVEltJEgsW69Ed7v1uNs5+vprEecVvegTr5o3LzV9UflF8ye4wv65ZtjJdb+9uTHeYLwje0woWvWfGAQ1KBZTWyJeIWEGhs04vqhKbO
Dak+KmvjYh2U3BYYLKlvCDtYulFAeZlDZFZXPii+8ND279wFZmF53nzPqzjg1rlsSjNZLREZ3FIFkYkBFBDPqrQQ56OKcnh+YStFhOrXz+Q3Sc0PrUMABWUuUqeTxjE9YEpng0wQ4ocHETICLfhofcvyqAD
Zb03is15Xzr6V/Z1SJ/pZzVhN7ov9PmW/LNqD7d+hCiemIvt2GAaO1FFtKaFCVvcO4jvfalyrpFwDOBvnEFR6OAQryyYT79jqYgGFP42Y7Acs7Jju/vizkNxo8szZvABUh3UgEli72AzcNDjSOxEkdU6yzS
ycYbh+26Cwi1KLmCB/4nTErUt2s4XtczRdA4Km+0pN8xpDyHrWf+Z4StKPCsxjwCHfIB+Y9ol1LT31k/MZ9o5TX/YKxp0gBqqfemrkkSVKDzEtk/KZGsVVkusVstpqGMdsEacdf8KoRI06yrgP6SQedwexk
Zm4Zhv6VUXOumPne0ZtMTSoXb8cuQ4PbmI056LYySLqdk2b89snVTE5QL/f+t3USY45MBcp67Boti2aFq0VYrkSSaw3GO2W9PfRZk+Uw8ubt1eO1MFB57dUSy6GL38SWWuqIrwCsmRJCwMaMUSIu+L2UOcn
N409rIMFEB908r3iMZoOUS1sDTxQotKW/6rx3LZKp8vS8rdTr4j++Ka22JjOCwBWFtExSoTgQ6YegG4wCy3PrbXq96a3/kStpqo04eeblfrqD1o1lNd/hJDqnALiszI2EJW+I/Ig61bHOpYKj8+S5M2Wen5
LtB+UOzcfTzc5zwGFhDQ9zjbkZVbvl1NvCU0pcJwjayKOFhdBDMJh9uP+60i27/9Zi7xeC/ivsT5fAEMh7JJVbjKLtQAjQNf5Bkj5gSvMjdEVjRUPVG2x4OJ5wHb6/wT5ciMjipV7w4mQqn45uMtmIHUpsk
TOx7SQAzLQfn1suvDStiS95Y1pbK6wKMV/86SvtvPjxQHZ3/LNq9i4j7gc8Np9/g250vcm+UeEXn4v3iWl3DhjXwXjCdnmNXPjguCawX2BUdhE32VERBNXU8d4KJitqDXSb2T/geaRRec8tMYtgjtiewO+q
vB2eLCdDR/SXBJyfjTyzBZ36SxP8VyD0GIMAdGpUjU395DW0sWzrNmNZMBAnMHF2wG3iLpsdViJfMzCH2Nf//kxey8qJeL1wAXq+9v9p1aFWVfBOSe6adhomGj8q/hApZI6zq0BdFhYYfuNS21et2fHtLcs
RWbav1DiObDWD3ktB3+t0TxNyaaHmGxKtVDG1KS1JDrddk+Aam9xynw0IgGExWfrqwO6nvePiGHMil6BJIaKpP4ocQP/muUu/YxgdEwEwYJKoZIhvcNAQkVMQYEBAEAAAAwWwYJKoZIhvcNAQkUMU4eTAB7
AEQAMwBEAEYAQgBEADUAQwAtADgAMQBFADcALQA0ADUAMQA0AC0AOAAxADYARgAtAEUAOQAxADgAOAA3ADcANAA2ADkAOAA5AH0wXQYJKwYBBAGCNxEBMVAeTgBNAGkAYwByAG8AcwBvAGYAdAAgAFMAbwB
mAHQAdwBhAHIAZQAgAEsAZQB5ACAAUwB0AG8AcgBhAGcAZQAgAFAAcgBvAHYAaQBkAGUAcjCCBGcGCSqGSIb3DQEHBqCCBFgwggRUAgEAMIIETQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQMwDgQI6JcEqu
Pyqx8CAgfQgIIEIDLZj9eiSr1DM8afM1CKB+VOPgMzvhrvmE1H1bjrAVGUp3R996v4xyOfsTvLHLgzTX0z1E/RXNA4CBU4TdHm8ptWw3jj5dHlEzOyoWMftSacouDLP7x3M3weea5Lv5BvmYKe8ZqQzNUbj
dhnVWIH3JuFKTm+CKM8nC/HELOdCC98v/hdv0b/1fy3QzXV+QCuJ9s2rfEBGmxmbgzYmRPlRHPzwN5r4qFlrDbIrbSk++6K4FJ3UTP7PD/HjLvyLRp6vzYKsd5igHbR/Qk4qpUAmWNJcyQVzoZTY034UKNX
3y6E+qHiL8r5VlsNUB3c8TizXZas71NJqqDG8yaPiaUE/HZyVZaps0zcKgbjNeyOTWdcjXN186gdAvAUIp4qm36Udo23oEcHtDtbi+Ia+IG8ca9B37cO0fbUgbNF8ePcjNYHiNKlRkZhwwALn+WjuW//bqV
6a20pINZKCNAXD34wGH2T/eFSKcgfjPqYwRbovEvQOki0sMKT8i5kXbJx5nvVEb4g3hO9k7kz05MUOYCu7FQg/J6l3BPMCKR02lOr0KWIrlyK+MzNJEQ1S6OboEF0rLSTHUHUTScHjxU4q6FonC7+dJY5pL
iCa0WzhvH6oCieY0v6mYnnOlwxK5dxllC8KKdDV4nJYha9DBivBbJEpVUEygZ/4WemGPdqExYcuB9euQ0RFpO7tVk4NAdZfnMfP8gAi8lGSGIyn1lz7t0AxyUPr0QZZr7wgpK3doTSr7j3G/n1DOKZUkuBN
CqhVO9muTOGlhblXCT4NMdRGZI+qJj+/0OEJXinvRGc7pMtMhbL6G8rSGWev7NZfmktHdC/W1VgopMzJsavpVw98WCWjz/gQYt3jc5RFCehH9NpiUFWCSbJTYqlXOfbEB3koIspX7+0hpYxCLLm0Lw+O0PK
vRHsL6AjnsyZITwnnizC/nhW4GfFKyu7ZQ/SdKq2oOWZL5nXc+tMV2KQsOzf/U1Wlu6jmlqGwS5ZOHhcGm91YLdHsBQ+KnI64ehvGQrb/CEgGz76LH/p7QhRno8c6XZt8wGQTfvX351nj8Doytx7gf1wboT
ox3VyQyQxm9lyYWhN1HlCkyJsx9hiWoOIyK4iKUyHX/1rZLRxXFPaOTBbunjSGvDY+bI6IaYtMXIqy8DkWy8KR4g/zmoKcsY8SLt8eNdM2HVX7FO3hjYnPZOhfiFZU9cBifBf+R4BIJE+8OOMtpC2adJK5J
Lia1tZdjkfMyOIfYBNLNP5GXKPKnrEd3YOG8b4cnzs9MFNgT7VLg/5Lgz8EOlRaMwRm1NObTHqAX1nVjmxbdKYvsSuJ5lATkGFgvMYC7xqnY2jkQDOGgMIKzpwMjHAbvYYmPMIYdnrd8lxbJDYyjBdG+i4h
tRfuXKlpPr/CSiQppD+HRndqLf4XzA7MB8wBwYFKw4DAhoEFGHc0Fq9VcSMZ3WjK2pi+Xp/V5kqBBRv6dOxMFKx5SsNoj74lWmA1Ua6QwICB9A=

向我展示的是这些通用步骤:

openssl genrsa -out privatekey.pem 1024
openssl req -new -x509 -key privatekey.pem -out publickey.cer -days 10000
openssl pkcs12 -export -out public_privatekey.pfx -inkey privatekey.pem -in publickey.cer

上面的命令确实产生了一个 pfx 将通过构造函数

# use openssl generic pfx
$pfx = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList "C:\Vault\OpenSSL\Certificates\API\public_privatekey.pfx"

If (-not $pfx.HasPrivateKey)
{
    throw [System.Exception]::new("The openssl generic certificate is incompatible with the security requirements.")
}

如果我引用 PFX 文件,它确实会通过构造函数并正常工作!?如果我再次传递原始文件字节,它会起作用吗?!我为自动化编写的流程中的哪些地方失败了,而过于 generic/simple 的流程却有效?


# use openssl generic pfx
[Byte[]]$pfxBytes = [System.IO.File]::ReadAllBytes("C:\Vault\OpenSSL\Certificates\API\public_privatekey.pfx")
$pfx = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList (,$pfxBytes)

If (-not $pfx.HasPrivateKey)
{
    throw [System.Exception]::new("The openssl generic certificate is incompatible with the security requirements.")
}

--更新--

使用 OpenSSL 方式在 genrsa 和 pkcs12 命令上使用未加密的 -passin pass: 和 -passout pass: 因此它们将被视为空白。这似乎可行,但是我的同事和我自己很好奇,如果在 pfx 上没有加密的私钥和导出密码是最佳实践。如果不是,我们如何才能达到标准?

openssl.exe rand -out C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration.rnd -base64 4096
openssl.exe genrsa -rand "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration.rnd" -out "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-private-key.pem" 2048
openssl.exe genrsa -rand "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration.rnd" -out "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-private-key-encrypted.pem" 2048
openssl.exe rsa -in "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-private-key.pem" -pubout -out "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-privatekey-corresponding-public-key.pem"
openssl.exe rsa -in "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-private-key.pem" -RSAPublicKey_out -out "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-privatekey-corresponding-rsa-public-key.pem"
openssl.exe req -x509 -days 90 -key "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-private-key.pem" -out "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-certificate.cer" -subj "/C=US/ST=CA/L=Newport Beach/O=AutoNow Inc/OU=Application Development/CN=*.autonow.com"
openssl.exe req -new -key "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-private-key.pem" -out "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-certificate-signature.csr" -subj "/C=US/ST=CA/L=Newport Beach/O=AutoNow Inc/OU=Application Development/CN=*.autonow.com"
openssl.exe pkcs12 -export  -aes256 -CSP "Microsoft Enhanced RSA and AES Cryptographic Provider" -name "" -out "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration.pfx" -inkey "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-private-key.pem" -in "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration-certificate.cer" -passout pass:
openssl.exe pkcs12 -out "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration.pem" -in "C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration.pfx" -clcerts -aes256 -CSP "Microsoft Enhanced RSA and AES Cryptographic Provider" -passout pass: -passin pass:

# This now works
[Byte[]]$pfxBytes = [System.IO.File]::ReadAllBytes("C:\Vault\OpenSSL\Certificates\API\customer-support-administration\customer-support-administration.pfx")
$pfx = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList (,$pfxBytes)

If (-not $pfx.HasPrivateKey)
{
    throw [System.Exception]::new("The certificate is incompatible with the security requirements.")
}

$base64Pfx = [System.Convert]::ToBase64String($pfxBytes)

# moment of truth instantiate the certificate using the security package code for updated openssl commands
[Byte[]]$pfxBytes = [Convert]::FromBase64String($base64Pfx)
$pfx = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList (,$pfxBytes)

If (-not $pfx.HasPrivateKey)
{
    throw [System.Exception]::new("The rehydrated certificate is incompatible with the security requirements.")
}

$pfx | select *

$base64Pfx = [System.Convert]::ToBase64String($pfxBytes)

# moment of truth instantiate the certificate using the security package code for idea 1
[Byte[]]$pfxBytes = [Convert]::FromBase64String($base64Pfx)
$pfx = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList (,$pfxBytes)

If (-not $pfx.HasPrivateKey)
{
    throw [System.Exception]::new("The rehydrated certificate is incompatible with the security requirements.")
}

根据错误消息,您正在传递没有密码的证书的原始字节...

您创建的 PFX 文件似乎在使用 X509Certificate2 时需要密码。

尝试创建一个未设置密码的 PFX。

以及更新后的问题:

这取决于(软件开发中的几乎所有内容)。

这是一个关于证书文件管理的安全问题。

如果证书文件可以 "escape" 或比您想要的更宽,那么最好添加密码。

如果您可以锁定对证书文件的访问,那么应该没问题。

如果您想支持密码,则需要更改 C# 代码以将密码和 byte[] 传递给 X509Certificate2 构造函数。

如果您确实使用了密码,那么安全管理问题现在将转移到您的密码存储上。