7

I'd like to use the OpenSSL .Net wrapper to retrieve a certificate from a remote server to my C# code. Essentially, I'd like to replicate

openssl s_client -connect 192.168.254.13:636 -showcerts

.. and ultimate bring the results into an X509Certificate. Is this possible, and if so can anyone point me in the right direction?

KenD
  • 5,280
  • 7
  • 48
  • 85

4 Answers4

7

I think there are two parts to the question:

  1. How do you retrieve the server's certificate
  2. How do you retrieve the certificate's chain

To rertrieve the server's certificate you use SslStream whose methods are similar to .NET's own SslStream

var serverName = "...;
var client = new TcpClient(serverName, 443);            

// Create an SSL stream that will close the client's stream.
using (var sslStream = new SslStream(client.GetStream(),true))
{
    sslStream.AuthenticateAsClient(serverName);                
    var serverCertificate = sslStream.RemoteCertificate;
 }

It seems that OpenSSL.Net can't retrieve a certificate's chain. The -showcerts parameter uses the SSL_get_peer_cert_chain function which is not implemented in OpenSSL.NET.

If you don't mind mixing OpenSSL.Net and the built-in .NET classes, you can convert an OpenSSL.Net certificate to a .NET certificate and retrieve the chain using .NET's X509Chain.Build . You can convert the .NET certificates back to OpenSSL.NET certificates using the .NET certificate's RawData property.

var managedCert = new System.Security.Cryptography.X509Certificates.X509Certificate2(serverCertificate.DER);
var chain = new System.Security.Cryptography.X509Certificates.X509Chain();
chain.Build(managedCert);


foreach (var element in chain.ChainElements)
{
    var raw = element.Certificate.RawData;
    using (var bio = new BIO(raw))
    {
        var oc = OpenSSL.X509.X509Certificate.FromDER(bio);
    }
}

Perhaps you can use .NET's SslStream and X509Certificate2 object to do what you want using the raw certificate data without using OpenSSL.Net at all.

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
  • [Use a particular CA for a SSL connection](http://stackoverflow.com/questions/22516450/use-a-particular-ca-for-a-ssl-connection/23180787#23180787) will avoid the CA Zoo from the Windows certificate store for verification. You will have to provide the one trusted CA to verify the chain, however. If you know the CA that issued the certificate, then its best to use just that one CA instead of the hundreds available. – jww Apr 20 '14 at 09:58
  • @jww your proposition is a security risk that has already been exploited numerous times - most recently as a consequence of the Heartbleed exploit. CA certificates *have* been compromised and revoked in the past. By using a local storage as a CA you have no way of validating the certificate or knowing that it has been revoked. There is no "CA Zoo", it's just the way certificates work. – Panagiotis Kanavos Apr 23 '14 at 06:56
  • @Panagiotis - Peter Guttman talks about the CA Zoo and more in his [Engineering Security](https://www.cs.auckland.ac.nz/~pgut001/pubs/book.pdf) book. Its a great read, and I suggest you browse through it. Especially chapters 1 and 6 on PKI. I can't remember the last time I depended on the CA Zoo. The CA Zoo brought us DigiNotar issuing certificates for Google, Hotmail, Yahoo, et al and dumb clients accepting those certificates. It was an unacceptable and preventable failure. – jww Apr 23 '14 at 07:09
2

Try using the ServicePointManager.ServerCertificateValidationCallback. That will be called with the server's X509 certificate et voila

http://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.servercertificatevalidationcallback.aspx

Dave Lawrence
  • 3,843
  • 2
  • 21
  • 35
  • No good for me I'm afraid - I'm looking to use OpenSSL to retrieve certificates from non-HTTPS services. – KenD May 31 '12 at 14:34
2

In order to create the same functionality as s_client, you must probably take a look at the code of s_client.

You can find s_client inside the openssl-X.Y.Z.tar.gz/apps/s_client.c

Probably PEM_write_bio_X509 does the "printing" of X509Certificate:

if (c_showcerts)
    PEM_write_bio_X509(bio,sk_X509_value(sk,i));
}

But there is the connection part also...

ftp://ftp.openssl.org/source/openssl-1.0.1.tar.gz

jww
  • 97,681
  • 90
  • 411
  • 885
athoik
  • 363
  • 4
  • 8
  • I was hoping there would be some "easy" way of doing it using OpenSSL.net but it would appear not :( – KenD Jun 05 '12 at 13:26
1

To obtain a CRL, first check the certificate and its issuing certificate for a cRLDistributionPoints extension that contains a URI GeneralName. This extension is defined in RFC 3280, and it specifies a way for CAs to communicate the location of the CRL that corresponds to the certificate used to issue another certificate. Unfortunately, this extension is defined as being optional, and most root CAs do not use it.

Izzy
  • 106
  • 4
  • I'm not sure how this relates to my original question? I'm not interested in CRL's, it's the "raw" cert I'd like to grab ... – KenD Jun 05 '12 at 13:25