Back to feature list...

X.509 certificates

X.509 certificates are used in TLS/SSL to validate a server in order to make sure you are connecting to the right one. X.509 certificates can be used for client authentication as well. For more information, read our Introduction to Public Key Certificates.

Rebex EWS has its own Certificate class for working with X.509 v3 certificates. It provides the following operations:

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 EWS:

  • 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 client instance
    // ...
    
    // skip certificate validation (don't do this in production environment!)
    client.Settings.SslAcceptAllCertificates = true;
    
    // connect securely (SslMode.Explicit or SslMode.Implicit)
    client.Connect(hostname, SslMode.Explicit);
    
    ' create client instance
    ' ...
    
    ' let skip certificate validation (don't do this in production environment!)
    client.Settings.SslAcceptAllCertificates = True
    
    ' connect securely (SslMode.Explicit or SslMode.Implicit)
    client.Connect(hostname, SslMode.Explicit)
    
Tip: For more detailed information read the Introduction to Public Key Certificates article.

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 client instance
// ...

// register custom validation event handler
client.ValidatingCertificate += client_ValidatingCertificate;

// connect securely (SslMode.Explicit or SslMode.Implicit)
client.Connect(hostname, SslMode.Explicit);
' create client instance
' ...

' register custom validation event handler
AddHandler client.ValidatingCertificate, AddressOf client_ValidatingCertificate

' connect securely (SslMode.Explicit or SslMode.Implicit)
client.Connect(hostname, SslMode.Explicit)

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

Overriding SSL server name 

Server certificate's common name should specify the server hostname - this ensures that the server presents a certificate that actually belongs to it. If the names are mismatched, you can still work around it.

Certificate validation options 

Use Settings.SslServerCertificateValidationOptions property to specify various options for the build-in certificate verifier. For example:

Note: Please make sure you understand the implications of these options when using them in production environments.

Client certificate authentication 

Certificates with an associated private key can be used to authenticate the client to the server. See more on the authentication modes page.

Loading X.509 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);
' load a certificate with private key from a PFX file
Dim cert1 = Certificate.LoadPfx(pfxPath, pfxPassword)

' load a certificate without a private key from a DER file
Dim cert2 = Certificate.LoadDer(derPath)

' load a certificate from a DER file and a private key from a key file
Dim cert3 = Certificate.LoadDerWithKey(derPath, keyPath, keyPassword)

Saving X.509 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);
' 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.Base64Pkcs8, True)

Validating X.509 certificates 

To check whether a certificate is valid and trusted by Windows certificate infrastructure, use Certificate.Validate method.

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.

// 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);
' validate a certificate
Dim res1 = cert.Validate()
If Not res1.Valid Then
    Console.Write("Validation failed: {0} (error {1}).", res1.Status, res1.NativeErrorCode)
End If

' validate a server certificate for 'serverName',
' skip revocation check and don't care if it's expired or not valid yet
Dim res2 = cert.Validate(serverName, _
        ValidationOptions.SkipRevocationCheck Or _
        ValidationOptions.IgnoreTimeNotValid)
If Not res2.Valid Then
    Console.Write("Validation failed: {0} (error {1}).", res2.Status, res2.NativeErrorCode)
End If

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 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);
' load a certificate from file
Dim cert = Certificate.LoadPfx(certPath, certPassword, KeySetOptions.Exportable)

' add the certificate to the "Personal Certificates" store
Dim store = New CertificateStore(CertificateStoreName.My)
store.Add(cert)

' find all not-expired certificates from issuer named "TestCA"
Dim dn = New DistinguishedName("CN=TestCA, O=Rebex, C=CZ")
Dim 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);
' load a certificate from file
Dim cert = Certificate.LoadDer(certPath)

' add the certificate to the "Trusted Root Certificates" store
Dim store = New CertificateStore(CertificateStoreName.Root)
store.Add(cert)
Tip: To manage Windows certificate store, you can use Internet Explorer (Tools / Internet options / Certificates) or the "Certificates" MMC snap-in.

Back to feature list...