Back to feature list...
X.509 certificates
On this page:
- Validating and examining server certificate
- Built-in certificate verifier
- Custom certificate validation
- Overriding SSL server name
- Certificate validation options
- Client certificate authentication
- Loading X.509 certificates
- Saving X.509 certificates
- Validating X.509 certificates
- Windows certificate store management
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
SslAcceptAllCertificatesproperty:// 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)
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:
SkipRevocationCheck– Skip revocation check.IgnoreCnNotMatch– Ignore server's certificate Common Name mismatch.IgnoreWrongUsage– Ignore server's certificate wrong usage.IgnoreTimeNotNested– Ignore improperly nested validity periods.AllowUnknownCa– Allow unknown certification authority.
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)
Back to feature list...