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...