【发布时间】:2021-07-21 18:48:22
【问题描述】:
我有一个嵌入式设备,它使用带有客户端证书身份验证的 TLS 1.2 安全通道通过 websocket 协议连接到我的后端服务器。我的组织拥有自己的设备和后端服务器证书颁发机构。设备正在以.pfx 的格式向后端服务器生成其证书(没有完整的链)。以下是我的代码 sn-p
public static void ConfigureEndPoints(this KestrelServerOptions options)
{
var configuration = options.ApplicationServices.GetRequiredService<IConfiguration>();
foreach (var address in ipAddresses)
{
switch ((EndPointType)config.Scheme)
{
case EndPointType.Plain:
options.Listen(address, port);
break;
case EndPointType.WithClientCert:
if (!string.IsNullOrEmpty(config.RootCertFile))
mRootCertFileName = config.RootCertFile;
if (config.IntermediateCerts != null)
mIntermediateCertFileNames = config.IntermediateCerts;
options.Listen(address, port, listenOptions =>
{
listenOptions.UseHttps(config.FileName, config.Password, configureOptions =>
{
configureOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
configureOptions.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls | SslProtocols.Tls11;
configureOptions.ClientCertificateValidation += VerifyClientCertificate;
});
});
break;
case EndPointType.WithoutClientCert:
options.Listen(address, port, listenOptions =>
{
listenOptions.UseHttps(config.FileName, config.Password, configureOptions =>
{
configureOptions.ClientCertificateMode = ClientCertificateMode.NoCertificate;
configureOptions.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls | SslProtocols.Tls11;
});
});
break;
default:
Console.WriteLine($"Invalid scheme value {config.Scheme}");
break;
}
}
private static bool VerifyClientCertificate(X509Certificate2 cert, X509Chain chain, SslPolicyErrors sslPolicy)
{
List<X509Certificate2> intermediateCerts = null;
try
{
X509Certificate2 clientCert = new X509Certificate2(cert);
if (mIntermediateCertFileNames != null)
{
foreach (string certFileName in mIntermediateCertFileNames)
{
if (intermediateCerts == null)
intermediateCerts = new List<X509Certificate2>();
X509Certificate2 clientIntermediateCert = new X509Certificate2(certFileName);
intermediateCerts.Add(clientIntermediateCert);
}
}
else
{
return false;
}
List<X509Certificate2> additionalCerts = intermediateCerts.ToList();
if (!string.IsNullOrEmpty(mRootCertFileName))
additionalCerts.Add(new X509Certificate2(mRootCertFileName));
else
{
return false;
}
bool status = VerifyCertificate(clientCert, additionalCerts);
if (status)
{
if (!(clientCert.NotAfter.ToUniversalTime() >= DateTime.Now.ToUniversalTime() &&
clientCert.NotBefore.ToUniversalTime() <= DateTime.Now.ToUniversalTime()))
{
status = false;
}
}
return status;
}
catch(Exception e)
{
return false;
}
}
static bool VerifyCertificate(X509Certificate2 clientCert, List<X509Certificate2> additionalCerts)
{
bool status = true;
bool thumbPrintMatch;
var chain = new X509Chain();
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreWrongUsage;
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
foreach (var cert in additionalCerts)
{
chain.ChainPolicy.ExtraStore.Add(cert);
}
try
{
status = chain.Build(clientCert);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
if (status)
{
if (chain.ChainElements.Count != chain.ChainPolicy.ExtraStore.Count + 1)
{
return false;
}
for(var i = 1; i < chain.ChainElements.Count; i++)
{
thumbPrintMatch = false;
for(var j = 0; j <= i; j++)
{
if(chain.ChainElements[i].Certificate.Thumbprint == chain.ChainPolicy.ExtraStore[j].Thumbprint)
{
thumbPrintMatch = true;
break;
}
}
if (!thumbPrintMatch)
{
return false;
}
}
}
else
return false;
return status;
}
当我在 Windows 商店中添加所有必需的根证书和中间证书时,上面的代码在 Windows 10 上运行得非常好。 status = chain.Build(clientCert); 提供status as true 并且还提供chain.ChainElements.Count 为4,这是正确的,即它正在构建从叶证书到根CA 的设备证书的完整链(总共4 个)。所有这些在Windows 上都可以正常工作而无需添加@ 987654329@标志。
现在在 Linux (CentOS7) 上,我在 /etc/pki/ca-trust/source/anchors 文件夹中添加了 TestRootCA.crt、DeviceIntermediate1.crt 和 DeviceIntermediate2.crt 并运行了 update-ca-trust extract 命令。以下是之后的观察:-
-
status = chain.Build(clientCert);不会返回true,直到我添加chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;标志。我不想添加这个标志来实现严格的安全约束。 -
如果我添加了
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;标志,那么chain.ChainElements.Count也只给出 1,即设备的叶证书。无法构建完整的链。
我还做了一件事,如果我让我的设备以.p12 格式生成具有完整链的证书,那么我的服务器就能够正确地对其进行身份验证。但是我不确定修改设备以提供完整链证书是否正确?是否存在一些安全威胁?
.NET CORE 在哪里搜索所有信任证书?
如何修改我的代码,以便我也可以对 linux 环境实施严格的安全约束,.pfx 无需发送设备链。
希望我能够解释所有事情。任何与此相关的想法都会有很大帮助。
【问题讨论】:
-
它在
certs目录和cert.pem文件中查找openssl version -d报告的任何目录。开始调试的地方是第一个丢失的证书,例如中间设备 2. -
它在 /etc/pki/tls/cert.pem 文件中可用。 cert.pem 文件中提供了所有三个 CA TestRootCA、DeviceIntermediate1CA 和 DeviceIntermediate2CA。
-
嗯。如果
openssl verify -show_chain clientcert.pem成功并且看起来正确,那么 X509Chain 应该可以工作。如果这不起作用,那么 OpenSSL 不喜欢您的 CA/链的某些特征,并且 X509Chain 将不起作用。 (如果它“应该有效,但无效”,请在 github.com/dotnet/runtime/issues 上打开一个问题,但除非我们可以在本地重现该错误,否则我们将无能为力。) -
我收到
error 20 at 0 depth lookup: unable to get local issuer certificate的错误。当我跑openssl verify -show_chain clientcert.pem。对此有任何想法。 -
嗯,这就是 .NET 不喜欢链的原因,那么 :)。在 Windows 上工作而不是在 OpenSSL 上工作很少见,但确实会发生。如果不查看客户端证书(公共部分)和颁发者证书的示例,我认为没有什么好方法可以提供帮助。
标签: .net-core tls1.2 client-certificates