从远程主机自动下载X509证书链 [英] Automated downloading of X509 certificate chain from remote host

查看:101
本文介绍了从远程主机自动下载X509证书链的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一些.net代码,这些代码将在我们的一台服务器上无计划地运行。它的部分执行要求它执行一个Java可执行文件,该文件通过SSL与某些Web资源和服务进行对话。

I am building some .net code that will run unattended on a scheduled basis on one of our servers. Part of its execution requires that it execute a Java executable which talks to some web resources and services over SSL.

如果Java通过SSL和它没有远程证书链中的每个证书。因此,在.NET中,我需要能够指定 https:// 资源,并需要它来本地下载整个远程链。

Java will absolutely throw a fit if it's doing something over SSL and it doesn't have every single certificate in the remote certificate's chain. So in .NET I need to be able to specify an https:// resource and need it to download the entire remote chain locally.

为什么要自动执行此操作?因为我想简化部署并且不必重复执行4次,而每次Oracle的证书之一过期时都要重复一次。

Why do I want to do this automatically? Because I want to make deployment simple and to not have to do this 4 times, and then again every time one of Oracle's certificates expires.

我这样做是:

 X509Certificate2 lowestCert = SecurityHelper.DownloadSslCertificate(keyDownloadLocation);

        X509Chain chain = new X509Chain();
        chain.Build(lowestCert);

        int counter = 0;
        foreach (X509ChainElement el in chain.ChainElements) {
            //Extract certificate
            X509Certificate2 chainCert = el.Certificate;

            //Come up with an alias and save location
            string alias = certBaseName + counter;
            string localLocation = Path.GetDirectoryName(
                   System.Reflection.Assembly.GetEntryAssembly().Location
                   ) + @"\" +alias + ".cer";

            //Save it locally
            SecurityHelper.SaveCertificateToFile(chainCert, localLocation);

            //Remove (if possible) and add to java's keystore
            deleteKeyFromKeystore(
                   javaFolder,
                   alias,
                   certKeyStore,
                   SecurityHelper.GetEncryptedAppSetting("JavaKeystorePassword")
            );

            addKeytoKeyStore(
                   localLocation,
                   javaFolder,
                   alias,
                   certKeyStore,
                   SecurityHelper.GetEncryptedAppSetting("JavaKeystorePassword")
            );

            //Then delete 
            if (File.Exists(localLocation)) File.Delete(localLocation); 

            counter++;
        }

SecurityHelper.DownloadSslCertificate 是一种自定义方法,可以从网站网址创建X509Certificate2。

SecurityHelper.DownloadSslCertificate is a custom method that creates an X509Certificate2 from a a website url.

cert 是最低级别的证书,我可以收回,但是我不能做的就是获得链中的所有东西。如果计算机上尚未安装其余的链,则 chain.ChainElements 仍然只有1级。我的问题是,这是一个全新的URL,具有(机器上)完全未知的证书,我想进入堆栈并递归下载每个证书。

cert is the lowest-level certificate and I can get that back, but what I can't do is get everything in the chain. chain.ChainElements is still only 1 level deep if the rest of the chain isn't already installed on the machine. My problem is that this is a brand new URL with totally unknown (to the machine) certificates, and I want to go up the stack and recursively download every one.

是有没有办法找到机器未知的URL并以编程方式下载链中的每个证书?

Is there a way to hit a URL unknown to the machine and programmatically downloading every certificate in the chain?

编辑:这是我下载SSL证书的方式:

public static X509Certificate2 DownloadSslCertificate(string strDNSEntry)
    {
        X509Certificate2 cert = null;
        using (TcpClient client = new TcpClient())
        { 
            client.Connect(strDNSEntry, 443);

            SslStream ssl = new SslStream(client.GetStream(), false,
                new RemoteCertificateValidationCallback(
                        (sender, certificate, chain, sslPolicyErrors) => {
                            return true;
                        }
                    ), null);
            try
            {
                ssl.AuthenticateAsClient(strDNSEntry);
            }
            catch (AuthenticationException e)
            {
                ssl.Close();
                client.Close();
                return cert;
            }
            catch (Exception e)
            {
                ssl.Close();
                client.Close();
                return cert;
            }
            cert = new X509Certificate2(ssl.RemoteCertificate);
            ssl.Close();
            client.Close();
            return cert;
        }
    }

编辑#2获取远程解决方案对我有用的SSL证书是捕获在SslStream.AuthenticateAsClient(url)期间发生的验证回调中的链;

 private static X509ChainElementCollection callbackChainElements = null;
 private static bool CertificateValidationCallback(
     Object sender,
     X509Certificate certificate,
     X509Chain chain,
     SslPolicyErrors sslPolicyErrors)
 {
     callbackChainElements = chain.ChainElements;
     return true;
 }

然后使用此回调启动验证,我有类似以下内容:

And then to kickoff the validation with this callback, I had something like:

public static X509Certificate2 DownloadSslCertificate(string url)
{
    X509Certificate2 cert = null;
    using (TcpClient client = new TcpClient())
    { 
        client.Connect(url, 443);

        SslStream ssl = new SslStream(client.GetStream(), false, CertificateValidationCallback, null);
        try
        {
            ssl.AuthenticateAsClient(url); //will call CertificateValidationCallback
        }

...等

然后在 AuthenticateAsClient 完成时,将本地 callbackChainElements 变量设置为 X509ChainElement 的集合。

Then by the time AuthenticateAsClient has finished, the local callbackChainElements variable is set to a collection of X509ChainElement.

推荐答案

实际上我所做的事情与此非常相似使用Powershell。

Actually I did something very similar to this using Powershell.

有一个正在更改ServicePointManager以忽略SSL验证(这听起来很合理,因为您可能没有本地根证书)。您要将ServerCertificateValidationCallback设置为true,这表明您正在使用自定义验证(或者在您的情况下,可能没有验证)。

One piece is changing ServicePointManager to ignore SSL validation (since you may not have the root certs locally, it sounds). It's ServerCertificateValidationCallback that you want to set to true, which tells it you're using a custom validation (or in your case, perhaps no validation).

您的链条元素大部分都在那里。您可以使用Export方法将证书导出到字节数组中:

From there, you're most of the way there with your chainelements. You can use the Export method to export the cert into a byte array:

foreach (X509ChainElement el in chain.ChainElements) {
 var certToCreate = el.Certificate.Export(X509ContentType.Cert);
  ...
}

从那里开始只是做一件事情您想要的字节数组。您可以将其传递给另一个证书对象的构造函数,然后将其导入Java密钥库中。

From there it's just a matter of doing what you want with the byte array. You can pass it to a constructor for another certificate object, which you can then import into the Java keystore.

希望有帮助,如果您还有其他疑问,请告诉我。 。

Hope that helps, please let me know if you have further questions.

编辑:实际上,我刚刚在在.NET 中使用X.509证书的技巧。作者建议不要直接从字节数组中写入数据,因为它将临时文件写入不会被清理的目录中。因此,他的建议是将字节数组写入磁盘,然后在完成后手动清理它。

EDIT: Actually, I just noticed this post on tips working with X.509 certificates in .NET . The author recommends against writing directly from a byte array because it writes the temp file to a directory that doesn't get cleaned up. So his suggestion is to write the byte array to disk, and then manually clean it up when you're done.

这篇关于从远程主机自动下载X509证书链的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆