Within a web browser, is it possible for JavaScript to obtain information about the HTTPS Certificate being used for the current page?

Is there a method for JavaScript running in a browser to determine which CA certificate is being used to authenticate the remote host for the browser's current HTTPS connection, and also obtain properties of that certificate, such as the name of the CA?

If not, are there any other options for programatically obtaining this information, such as ActiveX, Java, CGI on the server side, ...?


Solution 1:

You can use the opensource Forge project to do this. It implements SSL/TLS in JavaScript. You can make an ajax call to the server and use a callback to inspect the certificate. Keep in mind that the server is the one sending the JavaScript so this shouldn't be used to determine whether or not you trust the server the JavaScript is from. The Forge project does allow cross-domain requests, so if you are using this for trust, you can load the Forge JavaScript from a server you already trust and then contact the server you don't yet trust. However, unless that other server provides a cross-domain policy, you will not be able to perform the cross-domain request.

https://github.com/digitalbazaar/forge/blob/master/README.md

The blog links in the README provide more information on how Forge can be used and how it works.

Solution 2:

Copying my own answer from Is there any way to access certificate information from a Chrome Extension

2018 answer: yes, in Firefox 62

You'll need to make a WebExtension, which is also called a browser extension.

See accessing security information on MDN

You can also check out the docs for:

  • getSecurityInfo
  • SecurityInfo
  • CertificateInfo.

You'll need Firefox 62.

Here's a working background.js

var log = console.log.bind(console)

log(`\n\nTLS browser extension loaded`)

// https://developer.chrome.com/extensions/match_patterns
var ALL_SITES = { urls: ['<all_urls>'] }

// Mozilla doesn't use tlsInfo in extraInfoSpec 
var extraInfoSpec = ['blocking']; 

// https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webRequest/onHeadersReceived
browser.webRequest.onHeadersReceived.addListener(async function(details){
    log(`\n\nGot a request for ${details.url} with ID ${details.requestId}`)

    // Yeah this is a String, even though the content is a Number
    var requestId = details.requestId

    var securityInfo = await browser.webRequest.getSecurityInfo(requestId, {
        certificateChain: true,
        rawDER: false
    });

    log(`securityInfo: ${JSON.stringify(securityInfo, null, 2)}`)

}, ALL_SITES, extraInfoSpec) 

log('Added listener')

manifest.json:

{
    "manifest_version": 2,
    "name": "Test extension",
    "version": "1.0",
    "description": "Test extension.",
    "icons": {
        "48": "icons/border-48.png"
    },
    "background": {
        "scripts": ["background.js"]
    },
    "permissions": [
        "webRequest",
        "webRequestBlocking",
        "<all_urls>"
    ]
}

enter image description here

It also may be implemented in Chromium once this code is merged.

Solution 3:

JavaScript running in the web browser does not have access to the certificate information. The certificate information is also not passed through HTTP to the application. My research indicates that there is no way for the web application to determine if a man-in-the-middle attack has injected a bogus certificate somewhere between the host and client.