I have this code:
string certificateFilePath = @"C:\Users\Administrator\Documents\Certificate.pfx";
string certificateFilePassword = "Some Password Here";
X509Certificate clientCertificate = new X509Certificate(certificateFilePath, certificateFilePassword);
TcpClient client = new TcpClient(host, port);
SslStream stream = new SslStream(client.GetStream(), false, (sender, certificate, chain, errors) => true);
X509CertificateCollection clientCertificates = new X509CertificateCollection {clientCertificate};
stream.AuthenticateAsClient(host, clientCertificates, SslProtocols.Tls, false);
When I run the code in a Console Application, everything works fine, stream.IsAuthenticated
and stream.IsMutuallyAuthenticated
return true
and stream.LocalCertificate
contains the correct certificate object.
However when running the exact same code in a Windows Service (as LOCAL SYSTEM user)
, although stream.IsAuthenticated
returns true
, stream.IsMutuallyAuthenticated
returns false
and stream.LocalCertificate
returns null
.
This happens while in both scenarios, after the first line is ran clientCertificate
loads the correct certification data and contains the correct information for Certificate's Subject
and Issuer
.
I have also tried forcing the SslStream to pick the Certificate using this code:
string certificateFilePath = @"C:\Users\Administrator\Documents\Certificate.pfx";
string certificateFilePassword = "Some Password Here";
X509Certificate clientCertificate = new X509Certificate(certificateFilePath, certificateFilePassword);
TcpClient client = new TcpClient(host, port);
SslStream stream = new SslStream(client.GetStream(), false, (sender, certificate, chain, errors) => true, (sender, host, certificates, certificate, issuers) => clientCertificate);
X509CertificateCollection clientCertificates = new X509CertificateCollection {clientCertificate};
stream.AuthenticateAsClient(host, clientCertificates, SslProtocols.Tls, false);
However the code still doesn't work and stream.IsMutuallyAuthenticated
returns false
and stream.LocalCertificate
returns null
.
I have been exploring this for a few days now and I can't figure it out. Any help is highly appreciated.
Edit: After trying the certificate with WinHttpCertCfg tool it turns out that unlike similar question(s), LOCAL SYSTEM account already has access to the private key for the target certificate as you can see in the picture below: Therefore the problem still remains unsolved.
答案 0 :(得分:3)
我在玩X509课程时终于使代码工作了。
这是适用于我的代码:
string host = "The Host";
int port = 777;
string certificateFilePath = @"C:\Users\Administrator\Documents\Certificate.pfx";
string certificateFilePassword = "Some Password Here";
X509Certificate clientCertificate = new X509Certificate(certificateFilePath, certificateFilePassword);
X509Certificate2 clientCertificate2 = new X509Certificate2(clientCertificate); //<== Create a X509Certificate2 object from the X509Certificate which was loaded from the file. The clientCertificate2 loads the proper data
TcpClient client = new TcpClient(host, port);
SslStream stream = new SslStream(client.GetStream(), false, (sender, certificate, chain, errors) => true);
X509CertificateCollection clientCertificates = new X509CertificateCollection { clientCertificate2 }; //<== Using the clientCertificate2 which has loaded the proper data instead of the clientCertificate object
stream.AuthenticateAsClient(host, clientCertificates, SslProtocols.Tls, false);
这样我的代码就能从系统中找到合适的X509Store,证书和私钥。
我已经通过经验弄清楚了这一点。我找不到一个明确的解释,为什么它应该在MSDN上这样。
答案 1 :(得分:0)
我们用于此类服务问题的一种调试技术是使用PsExec之类的实用程序。这将允许您将交互式流程作为必要的服务帐户运行。
-s在系统帐户中运行该过程。
帮助内容会说&#34;远程进程&#34;,但它也可以用于本地进程。
例如, 在具有管理员权限的命令提示符
中运行以下命令后,下面将为您提供系统帐户的命令提示符PsExec.exe -s cmd
在命令窗口中,您可以使用WhoAmI
命令
C:\Windows\system32>whoami
nt authority\system
这将使您能够进行一些交互式测试以尝试不同的组合。
SYSTEM帐户在本地计算机中具有maximum possible privilege。
您还会看到,建议您创建自定义帐户来运行服务。但是,这有保留另一个密码的头脑。在较新版本的Windows中,有一个managed service accounts。这可能是更好的选择。
托管服务帐户和虚拟帐户 - 旨在为应用程序提供自己帐户的隔离,同时无需管理员手动管理这些帐户的SPN和凭据。