# Untrusted SSL Certificates

> Details on how Selenium 2 accepted untrusted SSL certificates

URL: https://deploy-preview-2974--selenium-dev.netlify.app/documentation/legacy/selenium_2/ssl_certs/
Site index: https://deploy-preview-2974--selenium-dev.netlify.app/llms.txt

---

This documentation previously located [on the wiki](https://github.com/SeleniumHQ/selenium/wiki/Untrusted-SSL-Certificates)

## Introduction
This page details how WebDriver is able to accept untrusted SSL certificates, allowing users to test trusted sites in a testing environment, where valid certificates usually do not exist. This feature is turned on by default for all supported browsers (Currently Firefox).

## Firefox
### Outline of solution
Firefox has an interface for overriding invalid certificates, called nsICertOverrideService. Implement this interface as a proxy to the original service - **unless** untrusted certificates are allowed. In that case, when asked about a certificate (a call to hasMatchingOverride for an invalid certificate) - indicate it's trusted.

### Implementation details
Implementing the idea is mostly straightforward - badCertListener.js is a stand-alone module, that, when loaded, registers a factory for returning an instance of the service. The interesting function is hasMatchingOverride:
```
WdCertOverrideService.prototype.hasMatchingOverride = function(
    aHostName, aPort, aCert, aOverrideBits, aIsTemporary)
```
The aOverrideBits and aIsTemporary are output arguments. This is where things get a bit tricky:
There are three possible override bits:
```
  ERROR_UNTRUSTED: 1,
  ERROR_MISMATCH: 2,
  ERROR_TIME: 4
```

It's impossible to just set them all, since Firefox expects a perfect match between the offences generated by the certificate and the function's return value: (security/manager/ssl/src/SSLServerCertVerification.cpp:302):

```
  if (overrideService)
  {
    PRBool haveOverride;
    PRBool isTemporaryOverride; // we don't care

    nsrv = overrideService->HasMatchingOverride(hostString, port,
                                                ix509, 
                                                &overrideBits,
                                                &isTemporaryOverride, 
                                                &haveOverride);
    if (NS_SUCCEEDED(nsrv) && haveOverride) 
    {
      // remove the errors that are already overriden
      remaining_display_errors -= overrideBits;
    }
  }

  if (!remaining_display_errors) {
    // all errors are covered by override rules, so let's accept the cert
    return SECSuccess;
  }
```

The exact mapping of violation to error code can be easily seen at security/manager/pki/resources/content/exceptionDialog.js (in Firefox source):
```
  var flags = 0;
  if(gSSLStatus.isUntrusted)
    flags |= overrideService.ERROR_UNTRUSTED;
  if(gSSLStatus.isDomainMismatch)
    flags |= overrideService.ERROR_MISMATCH;
  if(gSSLStatus.isNotValidAtThisTime)
    flags |= overrideService.ERROR_TIME;
```

The SSL status can be obtained from `"@mozilla.org/security/recentbadcerts;1"` usually - However, the certificate (and its status) are added to this service only **after** the call to `hasMatchingOverride`, so there is no easy way to find out the certificate's SSLStatus. Instead, the checks have to be executed manually.

Two checks are carried out:
* Calling `nsIX509Cert.verifyForUsage`
* Comparing hostname against `nsIX509Cert.commonName`. If those are not equal, `ERROR_MISMATCH` is set.

The second check indicates whether `ERROR_MISMATCH` should be set.
The first check should indicate whether `ERROR_UNTRUSTED` and `ERROR_TIME` should be set. Unfortunately, it does not work reliably when the certificate expired **and** is from an untrusted issuer. When the certificate has expired, the return code would be `CERT_EXPIRED` even if it is also untrusted. For this reason, the FirefoxDriver assumes that certificates will be untrusted - it **always** sets the `ERROR_UNTRUSTED` bit - the other two will be set only if the conditions for them are met.

This could pose a problem for someone testing a site with a valid certificate that does not match the host name it's served from (e.g. test environment serving production certificates). An additional feature for `FirefoxProfile` was added: `FirefoxProfile.setAssumeUntrustedCertificateIssuer`. Calling this function with `false` will turn the `ERROR_UNTRUSTED` bit off and allow a user to work in such situation.

## HTMLUnit
Not tested yet.

## IE
Not implemented yet.

## Chrome
Not implemented yet.
