More .NET libraries
-
Rebex Total Pack
All Rebex .NET libraries together
Back to feature list...
X.509 certificates
On this page:
Certificates are used in TLS/SSL to validate a server in order to make sure you are connecting to the right one. Certificates can be used for client authentication as well. For more information, read our Introduction to Public Key Certificates.
Validating and examining server certificate
When connecting securely, you should ensure you are really connected to the desired server. TLS/SSL provides it with a security certificate of the server. On the client side you should just verify that the server certificate of the current connection really comes from the server you want to connect to. There are following ways, how to do it using the Rebex TLS:
- By default, the server certificate is validated against Windows certificate infrastructure.
- If you cannot rely on the built-in certificate verifier, you can write your own certificate validation.
-
The certificate validation can be simply skipped by setting the
SslAcceptAllCertificates
property:// create an instance of TlsClientSocket // ... // skip certificate validation (don't do this in production environment!) socket.Parameters.CertificateVerifier = CertificateVerifier.AcceptAll;
' create an instance of TlsClientSocket ' ... ' skip certificate validation (don't do this in production environment!) socket.Parameters.CertificateVerifier = CertificateVerifier.AcceptAll
Built-in certificate verifier
When calling the Connect
method and no custom validation is configured,
the server certificate is validated using Windows CryptoAPI.
See what to do when a server certificate is not trusted.
Legacy Windows CE platforms don't natively support certificates signed using algorithms based on SHA-2 hashes. As a workaround for this major OS limitation, we introduced a built-in certificate validator in the 2016 R3 release.
Custom certificate validation
If you cannot relay on the certificate can be trusted by the Windows certificate infrastructure, you can implement your own validation:
Register an event handler before calling the Connect
method
// create an instance of TlsClientSocket // ... // register custom validation event handler socket.ValidatingCertificate += client_ValidatingCertificate;
' create an instance of TlsClientSocket ' ... ' register custom validation event handler AddHandler socket.ValidatingCertificate, AddressOf client_ValidatingCertificate
Implement the custom validation within the event handler
public void client_ValidatingCertificate(object sender, SslCertificateValidationEventArgs e) { // first try to use the default validation (against the Windows certificate store) ValidationResult res = e.CertificateChain.Validate(e.ServerName, 0); if (res.Valid) { e.Accept(); return; } // get server certificate of the current connection Certificate cert = e.CertificateChain[0]; // check the certificate is already known if (trustedThumbprints.Contains(cert.Thumbprint)) { e.Accept(); return; } // the certificate is not know yet - show it to user Console.WriteLine("Do you trust to the following certificate?"); Console.WriteLine(" Common name: {0}", cert.GetCommonName()); Console.WriteLine(" Thumbprint: {0}", cert.Thumbprint); Console.WriteLine(" Expires on: {0:d}", cert.GetExpirationDate()); // ask user for the answer // ... // accept or reject the certificate if (userAnswer) { e.Accept(); // OPTIONALY store the current certificate as trusted trustedThumbprints.Add(cert.Thumbprint); } else { e.Reject(); } }
Public Sub client_ValidatingCertificate(sender As Object, e As SslCertificateValidationEventArgs) ' first try to use the default validation (against the Windows certificate store) Dim res As ValidationResult = e.CertificateChain.Validate(e.ServerName, 0) If res.Valid Then e.Accept() Return End If ' get server certificate of the current connection Dim cert As Certificate = e.CertificateChain(0) ' check the certificate is already known If trustedThumbprints.Contains(cert.Thumbprint) Then e.Accept() Return End If ' the certificate is not know yet - show it to user Console.WriteLine("Do you trust to the following certificate?") Console.WriteLine(" Common name: {0}", cert.GetCommonName()) Console.WriteLine(" Thumbprint: {0}", cert.Thumbprint) Console.WriteLine(" Expires on: {0:d}", cert.GetExpirationDate()) ' ask user for the answer ' ... ' accept or reject the certificate If userAnswer Then e.Accept() ' OPTIONALY store the current certificate as trusted trustedThumbprints.Add(cert.Thumbprint) Else e.Reject() End If End Sub
Client certificate authentication
Client certificates are an optional way to authenticate the client to the server. This is only possible when connecting/authenticating to a TLS/SSL-capable HTTP server.
A certificate with an associated private key is needed for client authentication. Assign the Settings.SslClientCertificateRequestHandler
property
to an implementation of certificate request handler that is called when the HTTP server asks for client certificate.
a) Use the built-in StoreSearch
handler, that searches the user's certificate store for a first suitable certificate:
// set a certificate request handler socket.Parameters.CertificateRequestHandler = CertificateRequestHandler.StoreSearch;
b) Use the built-in PFX-based certificate request handler:
// load a certificate chain from a .P12 or .PFX file CertificateChain certificate = CertificateChain.LoadPfx("mycert.p12", "password"); // set a certificate request handler socket.Parameters.CertificateRequestHandler = CertificateRequestHandler.CreateRequestHandler(certificate);
c) Write a custom handler, for example to load the certificate from a .pfx/.p12 file:
private class MyCertRequestHandler : ICertificateRequestHandler { // This method is called during TLS/SSL negotiation // when the server requests client certificate authentication public CertificateChain Request(TlsSocket socket, DistinguishedName[] issuers) { // provide a certificate loaded from a .pfx/.p12 file return CertificateChain.LoadPfx(clientCertPath, clientCertPassword); } }
Don't forget to register the handler:
// set a certificate request handler socket.Parameters.CertificateRequestHandler = new MyCertRequestHandler();
Loading certificates
A certificate can be loaded from:
- PKCS #12 (.p7b) and PFX (.pfx) files. These usually contain a private key.
- DER files (.der/.cer), either binary or Base64-encoded. Private key can be loaded from an external key file.
// load a certificate with private key from a PFX file var cert1 = Certificate.LoadPfx(pfxPath, pfxPassword); // load a certificate without a private key from a DER file var cert2 = Certificate.LoadDer(derPath); // load a certificate from a DER file and a private key from a key file var cert3 = Certificate.LoadDerWithKey(derPath, keyPath, keyPassword);
Saving certificates
A certificate can be saved either to a PKCS #12 or PFX file or to a DER file.
A certificate's private key (if exportable) can be saved either as a part of PFX file or separately using PKCS #8, PuTTY or OpenSSH format.
// save a certificate with private key to a PFX file cert.Save(@"c:\MyData\cert.pfx", CertificateFormat.Pfx, "password"); // save a certificate to a DER file cert.Save(@"c:\MyData\cert.der", CertificateFormat.Der); // save certificate's private key to a base-64 encoded PKCS #8 file cert.SavePrivateKey(@"c:\MyData\cert.key", "password", PrivateKeyFormat.OpenSsh, true);
Stand-alone certificate validation
To jcheck whether a certificate is valid and trusted by Windows certificate infrastructure,
use Certificate.Validate
method.
// validate a certificate var res1 = cert.Validate(); if (!res1.Valid) Console.Write("Validation failed: {0} (error {1}).", res1.Status, res1.NativeErrorCode); // validate a server certificate for 'serverName', // skip revocation check and don't care if it's expired or not valid yet var res2 = cert.Validate(serverName, ValidationOptions.SkipRevocationCheck | ValidationOptions.IgnoreTimeNotValid); if (!res2.Valid) Console.Write("Validation failed: {0} (error {1}).", res2.Status, res2.NativeErrorCode);
Windows certificate store management
Microsoft Windows provides a system-wide storage for X.509 certificates and private keys. The storage is used by applications such as Internet Explorer, Google Chrome, Microsoft Outlook or Windows Live Mail.
Windows certificate store can be managed using Rebex TLS CertificateStore
class:
Manage personal certificate store
// load a certificate from file var cert = Certificate.LoadPfx(certPath, certPassword, KeySetOptions.Exportable); // add the certificate to the "Personal Certificates" store var store = new CertificateStore(CertificateStoreName.My); store.Add(cert); // find all not-expired certificates from issuer named "TestCA" var dn = new DistinguishedName("CN=TestCA, O=Rebex, C=CZ"); var found = store.FindCertificates(dn, CertificateFindOptions.IsTimeValid); Console.WriteLine("{0} certificates found.", found.Length); // remove the certificate from store store.Remove(cert);
Add a certificate to trusted root certification authorities store
// load a certificate from file var cert = Certificate.LoadDer(certPath); // add the certificate to the "Trusted Root Certificates" store var store = new CertificateStore(CertificateStoreName.Root); store.Add(cert);
Back to feature list...