更改 X509 证书的颁发者名称
Change issuer name of X509 certificate
7 年前有 same question 但使用外部库解决了。现在可以在没有外部库的情况下更改 X509Certificate2 Issuer Name
?
public static X509Certificate2 Create(string host)
{
var ecdsa = ECDsa.Create();
var request = new CertificateRequest($"CN={host}", ecdsa, HashAlgorithmName.SHA256);
var validFrom = DateTimeOffset.UtcNow;
var validUntil = DateTimeOffset.UtcNow.AddYears(5);
var certificate = request.CreateSelfSigned(validFrom, validUntil);
var certificateBytes = certificate.Export(X509ContentType.Pfx);
// ??? set issuer ???
return new X509Certificate2(certificateBytes);
}
对于自签名证书,更改颁发者名称只会生成不可验证的证书(除非您与颁发者共享私钥,这是一个坏主意)。
对于链签名证书,您可以使用 CertificateRequest.Create 方法之一来提供颁发者证书(其使用者名称将是新证书的颁发者名称),或者您可以提供颁发者名称和签名生成器(例如 X509SignatureGenerator.CreateForECDsa(key)
),用于完全控制(包括制作上述不可验证的证书)。
@bartojs 答案是正确的我必须使用 CertificateRequest.Create
.
我正在为我的 MITM 代理服务器应用程序创建自签名证书,所以这里是在 .Net Framework 4.7.2 中生成证书的工作代码,没有外部 .dll 库,如 Bouncy Castle 或 CERTENROLLIB
public static X509Certificate2 CreateMyCertificate(string host, bool isCA)
{
var validFrom = DateTimeOffset.UtcNow;
var validUntil = DateTimeOffset.UtcNow.AddYears(8);
X509Certificate2 certificate;
RSA rsaKey = Program.rootRSA;
if (isCA)
{
// create exportable Root private key
// will be used later as global variable Program.rootRSA
CspParameters cspParams = new CspParameters
{
KeyContainerName = Guid.NewGuid().ToString()
};
rsaKey = new RSACryptoServiceProvider(2048, cspParams);
}
// Request a certificate with the common name as the host using the key pair.
// Common Name (AKA CN) represents the server name protected by the SSL certificate.
var request = new CertificateRequest(
$"CN={host}",
rsaKey,
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1
);
// Add Certificate Extensions
request.CertificateExtensions.Add(
new X509EnhancedKeyUsageExtension(
new OidCollection
{
new Oid("1.3.6.1.5.5.7.3.1")
}, true)
);
if (isCA)
{
request.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, true, 1, false));
request.CertificateExtensions.Add(
new X509SubjectKeyIdentifierExtension(request.PublicKey, false));
request.CertificateExtensions.Add(
new X509KeyUsageExtension(X509KeyUsageFlags.CrlSign | X509KeyUsageFlags.KeyCertSign, false));
certificate = request.CreateSelfSigned(validFrom, validUntil);
}
else
{
SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder();
sanBuilder.AddDnsName(host.Replace("*.", ""));
request.CertificateExtensions.Add(sanBuilder.Build());
request.CertificateExtensions.Add(new X509Extension("2.5.29.35", Program.authorityKeyIdentifer, false));
request.CertificateExtensions.Add(new X509KeyUsageExtension(
X509KeyUsageFlags.KeyEncipherment, false));
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var unixTime = Convert.ToInt64((DateTime.UtcNow - epoch).TotalSeconds);
var serial = BitConverter.GetBytes(unixTime);
certificate = request.Create(Program.rootCert, validFrom, validUntil.AddDays(-5), serial);
certificate.PrivateKey = Program.rootCert.PrivateKey;
}
var certificateBytes = certificate.Export(X509ContentType.Pfx, "");
// return certificate with persisted private key
return new X509Certificate2(certificateBytes, "", X509KeyStorageFlags.Exportable);
}
然后像这样使用它:
- 创建全局变量并将其命名为
rootCert
和 rootRSA
- 在应用程序启动时检查计算机证书,如果未存储 CA,则使用
生成
rootCert = CreateMyCertificate("__MY_ROOT_CERTIFICATE", true);
- Export/Store
rootCert
到受信任的根位置
- 稍后如果有 https
connect
请求,我们可以使用 生成证书
CreateMyCertificate("whosebug.com", false);
- 当 chaining/creating
host
证书确保 rootCert
已定义,因为它将在 CreateMyCertificate()
方法中使用,下面一行
if (isCA){...}
else
{
certificate = request.Create(Program.rootCert, validFrom, validUntil.AddDays(-5), serial);
}
请注意为什么您不应该使用 CERTENROLLIB:
- 慢,因为它的操作需要直接从计算机证书中读取
- RSA 生成也比内置的 .net 4.7.2 慢
- 要获取私钥,我们首先需要安装证书,我们可以通过对计算机证书进行大量安装来导出到 PFX,它可以向您的计算机证书发送垃圾邮件。
7 年前有 same question 但使用外部库解决了。现在可以在没有外部库的情况下更改 X509Certificate2 Issuer Name
?
public static X509Certificate2 Create(string host)
{
var ecdsa = ECDsa.Create();
var request = new CertificateRequest($"CN={host}", ecdsa, HashAlgorithmName.SHA256);
var validFrom = DateTimeOffset.UtcNow;
var validUntil = DateTimeOffset.UtcNow.AddYears(5);
var certificate = request.CreateSelfSigned(validFrom, validUntil);
var certificateBytes = certificate.Export(X509ContentType.Pfx);
// ??? set issuer ???
return new X509Certificate2(certificateBytes);
}
对于自签名证书,更改颁发者名称只会生成不可验证的证书(除非您与颁发者共享私钥,这是一个坏主意)。
对于链签名证书,您可以使用 CertificateRequest.Create 方法之一来提供颁发者证书(其使用者名称将是新证书的颁发者名称),或者您可以提供颁发者名称和签名生成器(例如 X509SignatureGenerator.CreateForECDsa(key)
),用于完全控制(包括制作上述不可验证的证书)。
@bartojs 答案是正确的我必须使用 CertificateRequest.Create
.
我正在为我的 MITM 代理服务器应用程序创建自签名证书,所以这里是在 .Net Framework 4.7.2 中生成证书的工作代码,没有外部 .dll 库,如 Bouncy Castle 或 CERTENROLLIB
public static X509Certificate2 CreateMyCertificate(string host, bool isCA)
{
var validFrom = DateTimeOffset.UtcNow;
var validUntil = DateTimeOffset.UtcNow.AddYears(8);
X509Certificate2 certificate;
RSA rsaKey = Program.rootRSA;
if (isCA)
{
// create exportable Root private key
// will be used later as global variable Program.rootRSA
CspParameters cspParams = new CspParameters
{
KeyContainerName = Guid.NewGuid().ToString()
};
rsaKey = new RSACryptoServiceProvider(2048, cspParams);
}
// Request a certificate with the common name as the host using the key pair.
// Common Name (AKA CN) represents the server name protected by the SSL certificate.
var request = new CertificateRequest(
$"CN={host}",
rsaKey,
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1
);
// Add Certificate Extensions
request.CertificateExtensions.Add(
new X509EnhancedKeyUsageExtension(
new OidCollection
{
new Oid("1.3.6.1.5.5.7.3.1")
}, true)
);
if (isCA)
{
request.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, true, 1, false));
request.CertificateExtensions.Add(
new X509SubjectKeyIdentifierExtension(request.PublicKey, false));
request.CertificateExtensions.Add(
new X509KeyUsageExtension(X509KeyUsageFlags.CrlSign | X509KeyUsageFlags.KeyCertSign, false));
certificate = request.CreateSelfSigned(validFrom, validUntil);
}
else
{
SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder();
sanBuilder.AddDnsName(host.Replace("*.", ""));
request.CertificateExtensions.Add(sanBuilder.Build());
request.CertificateExtensions.Add(new X509Extension("2.5.29.35", Program.authorityKeyIdentifer, false));
request.CertificateExtensions.Add(new X509KeyUsageExtension(
X509KeyUsageFlags.KeyEncipherment, false));
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var unixTime = Convert.ToInt64((DateTime.UtcNow - epoch).TotalSeconds);
var serial = BitConverter.GetBytes(unixTime);
certificate = request.Create(Program.rootCert, validFrom, validUntil.AddDays(-5), serial);
certificate.PrivateKey = Program.rootCert.PrivateKey;
}
var certificateBytes = certificate.Export(X509ContentType.Pfx, "");
// return certificate with persisted private key
return new X509Certificate2(certificateBytes, "", X509KeyStorageFlags.Exportable);
}
然后像这样使用它:
- 创建全局变量并将其命名为
rootCert
和rootRSA
- 在应用程序启动时检查计算机证书,如果未存储 CA,则使用 生成
rootCert = CreateMyCertificate("__MY_ROOT_CERTIFICATE", true);
- Export/Store
rootCert
到受信任的根位置 - 稍后如果有 https
connect
请求,我们可以使用 生成证书
CreateMyCertificate("whosebug.com", false);
- 当 chaining/creating
host
证书确保rootCert
已定义,因为它将在CreateMyCertificate()
方法中使用,下面一行
if (isCA){...}
else
{
certificate = request.Create(Program.rootCert, validFrom, validUntil.AddDays(-5), serial);
}
请注意为什么您不应该使用 CERTENROLLIB:
- 慢,因为它的操作需要直接从计算机证书中读取
- RSA 生成也比内置的 .net 4.7.2 慢
- 要获取私钥,我们首先需要安装证书,我们可以通过对计算机证书进行大量安装来导出到 PFX,它可以向您的计算机证书发送垃圾邮件。