chrome.certificateProvider

Description: Use this API to expose certificates to the platform which can use these certificates for TLS authentications.
Availability: Since Chrome 46.
Permissions: "certificateProvider"

Important: This API works only on Chrome OS.

Usage

Typical usage of this API to expose client certificates to Chrome OS follows these steps:

  • The Extension registers for the events onCertificatesRequested and onSignDigestRequested.
  • During a TLS handshake, the browser receives a client certificate request. With a onCertificatesRequested event, the browser asks the Extension to report all certificates that it currently provides.
  • The Extension reports back with the currently available certificates, using the callback that was provided with the event.
  • The browser matches all available certificates with the client certificate request from the remote host. The matches are presented to the user in a selection dialog.
  • The user can select a certificate and thereby approve the authentication or abort the authentication.

    Certificate selection dialog

  • If the user aborts the authentication or no certificate matched the request, the TLS client authentication is aborted.
  • Otherwise, if the user approves the authentication with a certificate provided by this Extension, the browser requests the Extension to sign a digest to continue the TLS handshake. The request is sent as a onSignDigestRequested event.
  • This event contains a digest, declares which hash function was used to create the digest, and refers to one of the certificates that were reported by this Extension in reaction to the most recent certificate request. The Extension must create a signature for the given digest using the private key associated with the referenced certificate. Creating the signature might require prepending a DigestInfo and padding the result before the actual signing.
  • The Extension sends back the signature to the browser using the callback that was provided as part of the event. If the signature couldn't be calculated, the callback is called without signature.
  • If the signature was provided, the browser completes the TLS handshake.

The actual sequence of steps can be different. For example, the user will not be asked to select a certificate if the enterprise policy to automatically select a certificate is used (see AutoSelectCertificateForUrls and Chrome policies for users).

In the Extension, this can look similar to the following snippet:

      function onCertificatesRejected(rejectedCerts) {
        // If certificates were rejected by the API, log an error, for example.
        console.error(rejectedCerts.length + ' certificates were rejected.');
      }
      
      function reportCertificates(reportCallback) {
        var certs = [];
        // Fill |certs| with all certificates that this Extension provides.
        // For example:
        var certInfo = {
          certificate: new Uint8Array(...),
          supportedHashes: ['SHA256']
        };
        certs.push(certInfo);
      
        reportCallback(certs, function(rejectedCerts) {
          if (chrome.runtime.lastError) {
            // Handle API errors, like argument type errors.
            return;
          }
          if (rejectedCerts.length !== 0)
            onCertificatesRejected(rejectedCerts);
        });
      }
      
      // Returns a private key handle for the given DER-encoded certificate.
      // |certificate| is an ArrayBuffer.
      function getPrivateKeyHandle(certificate) {...}
      
      // If required, prepends |digest| with a DigestInfo and pads the result
      // according to the key type and the given Hash function.
      // |digest| is an ArrayBuffer. |hash| is a Hash. Returns an ArrayBuffer.
      function prepareDigest(digest, hash) {...}
      
      // Signs |digest| with the given private key. |digest| is an ArrayBuffer.
      // Returns the signature as ArrayBuffer.
      function signDigest(privateKey, digest) {...}
      
      function reportSignature(signRequest, reportCallback) {
        // Look up the handle to the private key of |signRequest.certificate|.
        var key = getPrivateKeyHandle(signRequest.certificate);
        if (!key) {
          // Handle if the key isn't available.
          console.error('Key for requested certificate no available.');
      
          // Abort the request by reporting the error to the API.
          reportCallback();
          return;
        }
      
        var preparedDigest = prepareDigest(signRequest.digest, signRequest.hash);
        var signature = signDigest(key, preparedDigest);
      
        reportCallback(signature);
      }
      
      chrome.certificateProvider.onCertificatesRequested.addListener(
          reportCertificates);
      chrome.certificateProvider.onSignDigestRequested.addListener(
          reportSignature);
      

Summary

Types
Hash
PinRequestErrorType
CertificateInfo
SignRequest
Methods
requestPin chrome.certificateProvider.requestPin(object details, function callback)
stopPinRequest chrome.certificateProvider.stopPinRequest(object details, function callback)
Events
onCertificatesRequested
onSignDigestRequested

Types

Hash

Enum
"MD5_SHA1", "SHA1", "SHA256", "SHA384", or "SHA512"

PinRequestErrorType

The types of errors that can be presented to the user through the requestPin function.
Enum
"INVALID_PIN", "INVALID_PUK", "MAX_ATTEMPTS_EXCEEDED", or "UNKNOWN_ERROR"

CertificateInfo

properties
ArrayBuffer certificate

Must be the DER encoding of a X.509 certificate. Currently, only certificates of RSA keys are supported.

array of Hash supportedHashes

Must be set to all hashes supported for this certificate. This extension will only be asked for signatures of digests calculated with one of these hash algorithms. This should be in order of decreasing hash preference.

SignRequest

properties
integer signRequestId

Since Chrome 57. Warning: this is the current Beta channel. Learn more.

The unique ID to be used by the extension should it need to call a method that requires it, e.g. requestPin.

ArrayBuffer digest

The digest that must be signed.

Hash hash

Refers to the hash algorithm that was used to create digest.

ArrayBuffer certificate

The DER encoding of a X.509 certificate. The extension must sign digest using the associated private key.

Methods

requestPin

chrome.certificateProvider.requestPin(object details, function callback)

Since Chrome 57. Warning: this is the current Beta channel. Learn more.

Requests the PIN from the user. Only one ongoing request at a time is allowed. The requests issued while another flow is ongoing are rejected. It's the extension's responsibility to try again later if another flow is in progress.

Parameters
object details

Contains the details about the requested dialog.

integer signRequestId

The ID given by Chrome in SignRequest.

enum of "PIN", or "PUK" (optional) requestType

The type of code requested. Default is PIN.

PinRequestErrorType (optional) errorType

The error template displayed to the user. This should be set if the previous request failed, to notify the user of the failure reason.

integer (optional) attemptsLeft

The number of attempts left. This is provided so that any UI can present this information to the user. Chrome is not expected to enforce this, instead stopPinRequest should be called by the extension with errorType = MAX_ATTEMPTS_EXCEEDED when the number of pin requests is exceeded.

function callback

Is called when the dialog is resolved with the user input, or when the dialog request finishes unsuccessfully (e.g. the dialog was canceled by the user or was not allowed to be shown).

The callback parameter should be a function that looks like this:

function(object details) {...};
object (optional) details
string (optional) userInput

The code provided by the user. Empty if user closed the dialog or some other error occurred.

stopPinRequest

chrome.certificateProvider.stopPinRequest(object details, function callback)

Since Chrome 57. Warning: this is the current Beta channel. Learn more.

Stops the pin request started by the requestPin function.

Parameters
object details

Contains the details about the reason for stopping the request flow.

integer signRequestId

The ID given by Chrome in SignRequest.

PinRequestErrorType (optional) errorType

The error template. If present it is displayed to user. Intended to contain the reason for stopping the flow if it was caused by an error, e.g. MAX_ATTEMPTS_EXCEEDED.

function callback

To be used by Chrome to send to the extension the status from their request to close PIN dialog for user.

The callback parameter should be a function that looks like this:

function() {...};

Events

onCertificatesRequested

Since Chrome 47.

This event fires every time the browser requests the current list of certificates provided by this extension. The extension must call reportCallback exactly once with the current list of certificates.

addListener

chrome.certificateProvider.onCertificatesRequested.addListener(function callback)
Parameters
function callback

The callback parameter should be a function that looks like this:

function(function reportCallback) {...};
function reportCallback

Call this exactly once with the list of certificates that this extension is providing. The list must only contain certificates for which the extension can sign data using the associated private key. If the list contains invalid certificates, these will be ignored. All valid certificates are still registered for the extension. Chrome will call back with the list of rejected certificates, which might be empty.

The reportCallback parameter should be a function that looks like this:

function(array of CertificateInfo certificates) {...};
array of CertificateInfo certificates

onSignDigestRequested

This event fires every time the browser needs to sign a message using a certificate provided by this extension in reply to an onCertificatesRequested event. The extension must sign the data in request using the appropriate algorithm and private key and return it by calling reportCallback. reportCallback must be called exactly once.

addListener

chrome.certificateProvider.onSignDigestRequested.addListener(function callback)
Parameters
function callback

The callback parameter should be a function that looks like this:

function( SignRequest request, function reportCallback) {...};
SignRequest request

Contains the details about the sign request.

function reportCallback

If no error occurred, this function must be called with the signature of the digest using the private key of the requested certificate. For an RSA key, the signature must be a PKCS#1 signature. The extension is responsible for prepending the DigestInfo prefix and adding PKCS#1 padding. If an MD5_SHA1 hash is to be signed, the extension must not prepend a DigestInfo prefix but only add PKCS#1 padding. If an error occurred, this callback should be called without signature.

The reportCallback parameter should be a function that looks like this:

function(ArrayBuffer signature) {...};
ArrayBuffer (optional) signature