.NET 5 无法导出 letsencrypt 证书私钥
.NET 5 fails to export letsencrypt certificate private key
我已经生成了让我们加密存储在 LocalMachine\My
中的证书。邮件服务器必须每 90 天更新一次证书。我的程序应该每 30 天获取最后一个有效证书、导出密钥和重启服务。
我在导出私钥时遇到问题。 Let's encrypt 证书不受密码保护。
我的错误:
Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: The requested operation is not supported. at System.Security.Cryptography.CngKey.Export(CngKeyBlobFormat format) at
System.Security.Cryptography.RSACng.ExportKeyBlob(Boolean includePrivateParameters) at
System.Security.Cryptography.RSACng.ExportParameters(Boolean includePrivateParameters) at
System.Security.Cryptography.RSA.WritePkcs1PrivateKey() at
System.Security.Cryptography.RSA.ExportRSAPrivateKey()
代码:
try
{
using X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
try
{
store.Open(OpenFlags.OpenExistingOnly);
X509Certificate2Collection collection = store.Certificates.Find(X509FindType.FindBySubjectName, "my.domain.name", true);
X509Certificate2 certificate = null;
foreach(X509Certificate2 item in collection)
{
if (certificate is null)
certificate = item;
else if (item.NotAfter > certificate.NotAfter)
certificate = item;
}
if(certificate is null)
{
logger.LogError($"Certificate not found.");
return;
}
byte[] certificateBytes = certificate.RawData;
char[] certificatePem = PemEncoding.Write("CERTIFICATE", certificateBytes);
RSA key = certificate.GetRSAPrivateKey();
byte[] privKeyBytes = key.ExportRSAPrivateKey(); //key.ExportPkcs8PrivateKey(); // CRASH
char[] privKeyPem = PemEncoding.Write("PRIVATE KEY", privKeyBytes);
string privateKey = $"{new string(privKeyPem).Replace("\r\n\n", "\n")}\n";
string certificateKey = $"{new string(certificatePem).Replace("\r\n\n", "\n")}\n";
await File.WriteAllTextAsync("mypath\key.private", privateKey);
await File.WriteAllTextAsync("mypath\key.public", certificateKey);
// service reboot....
}
catch (CryptographicException ex)
{
logger.LogError($"Certificate error - {ex}");
}
finally
{
store.Close();
}
}
catch(Exception ex)
{
logger.LogError(ex.ToString());
}
程序由在C:\Program Data\Microsoft\Crypto\RSA\MachineKeys
中具有读、写、修改、列表权限的用户运行
.net版本5.0.3
目标 os:windows 服务器 2016
这是因为 Windows 中的一个怪癖,其中 CNG 中的私钥有两个可导出性概念(纯文本可导出与加密可导出)。这是一个非常简单的解决方法:
PbeParameters simplePbe = new PbeParameters(
PbeEncryptionAlgorithm.TripleDes3KeyPkcs12,
HashAlgorithmName.SHA1,
1);
byte[] = key.ExportEncryptedPkcs8PrivateKey("temp", simplePbe);
using (RSA temp = RSA.Create())
{
temp.ImportEncryptedPkcs8PrivateKey("temp", exported, out _);
privKeyBytes = temp.ExportPkcs8PrivateKey();
}
char[] privKeyPem = PemEncoding.Write("PRIVATE KEY", privKeyBytes);
我已经生成了让我们加密存储在 LocalMachine\My
中的证书。邮件服务器必须每 90 天更新一次证书。我的程序应该每 30 天获取最后一个有效证书、导出密钥和重启服务。
我在导出私钥时遇到问题。 Let's encrypt 证书不受密码保护。
我的错误:
Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: The requested operation is not supported. at System.Security.Cryptography.CngKey.Export(CngKeyBlobFormat format) at
System.Security.Cryptography.RSACng.ExportKeyBlob(Boolean includePrivateParameters) at
System.Security.Cryptography.RSACng.ExportParameters(Boolean includePrivateParameters) at
System.Security.Cryptography.RSA.WritePkcs1PrivateKey() at
System.Security.Cryptography.RSA.ExportRSAPrivateKey()
代码:
try
{
using X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
try
{
store.Open(OpenFlags.OpenExistingOnly);
X509Certificate2Collection collection = store.Certificates.Find(X509FindType.FindBySubjectName, "my.domain.name", true);
X509Certificate2 certificate = null;
foreach(X509Certificate2 item in collection)
{
if (certificate is null)
certificate = item;
else if (item.NotAfter > certificate.NotAfter)
certificate = item;
}
if(certificate is null)
{
logger.LogError($"Certificate not found.");
return;
}
byte[] certificateBytes = certificate.RawData;
char[] certificatePem = PemEncoding.Write("CERTIFICATE", certificateBytes);
RSA key = certificate.GetRSAPrivateKey();
byte[] privKeyBytes = key.ExportRSAPrivateKey(); //key.ExportPkcs8PrivateKey(); // CRASH
char[] privKeyPem = PemEncoding.Write("PRIVATE KEY", privKeyBytes);
string privateKey = $"{new string(privKeyPem).Replace("\r\n\n", "\n")}\n";
string certificateKey = $"{new string(certificatePem).Replace("\r\n\n", "\n")}\n";
await File.WriteAllTextAsync("mypath\key.private", privateKey);
await File.WriteAllTextAsync("mypath\key.public", certificateKey);
// service reboot....
}
catch (CryptographicException ex)
{
logger.LogError($"Certificate error - {ex}");
}
finally
{
store.Close();
}
}
catch(Exception ex)
{
logger.LogError(ex.ToString());
}
程序由在C:\Program Data\Microsoft\Crypto\RSA\MachineKeys
.net版本5.0.3
目标 os:windows 服务器 2016
这是因为 Windows 中的一个怪癖,其中 CNG 中的私钥有两个可导出性概念(纯文本可导出与加密可导出)。这是一个非常简单的解决方法:
PbeParameters simplePbe = new PbeParameters(
PbeEncryptionAlgorithm.TripleDes3KeyPkcs12,
HashAlgorithmName.SHA1,
1);
byte[] = key.ExportEncryptedPkcs8PrivateKey("temp", simplePbe);
using (RSA temp = RSA.Create())
{
temp.ImportEncryptedPkcs8PrivateKey("temp", exported, out _);
privKeyBytes = temp.ExportPkcs8PrivateKey();
}
char[] privKeyPem = PemEncoding.Write("PRIVATE KEY", privKeyBytes);