gecko-dev/toolkit/devtools/security/auth.js

150 lines
4.4 KiB
JavaScript

/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/**
* An |Authenticator| implements an authentication mechanism via various hooks
* in the client and server debugger socket connection path (see socket.js).
*
* |Authenticator|s are stateless objects. Each hook method is passed the state
* it needs by the client / server code in socket.js.
*
* Separate instances of the |Authenticator| are created for each use (client
* connection, server listener) in case some methods are customized by the
* embedder for a given use case.
*/
let Authenticators = {};
/**
* The Prompt authenticator displays a server-side user prompt that includes
* connection details, and asks the user to verify the connection. There are
* no cryptographic properties at work here, so it is up to the user to be sure
* that the client can be trusted.
*/
let Prompt = Authenticators.Prompt = {};
Prompt.mode = "PROMPT";
Prompt.Client = function() {};
Prompt.Client.prototype = {
mode: Prompt.mode,
};
Prompt.Server = function() {};
Prompt.Server.prototype = {
mode: Prompt.mode,
/**
* Verify that listener settings are appropriate for this authentication mode.
*
* @param listener SocketListener
* The socket listener about to be opened.
* @throws if validation requirements are not met
*/
validateOptions() {},
/**
* Augment the service discovery advertisement with any additional data needed
* to support this authentication mode.
*
* @param listener SocketListener
* The socket listener that was just opened.
* @param advertisement object
* The advertisement being built.
*/
augmentAdvertisement(listener, advertisement) {
advertisement.authentication = Prompt.mode;
},
};
/**
* The out-of-band (OOB) cert authenticator is based on self-signed X.509 certs
* at both the client and server end.
*
* The user is first prompted to verify the connection, similar to the prompt
* method above. This prompt may display cert fingerprints if desired.
*
* Assuming the user approves the connection, further UI is used to assist the
* user in tranferring out-of-band (OOB) verification of the client's
* certificate. For example, this could take the form of a QR code that the
* client displays which is then scanned by a camera on the server.
*
* Since it is assumed that an attacker can't forge the client's X.509 cert, the
* user may also choose to always allow a client, which would permit immediate
* connections in the future with no user interaction needed.
*
* See docs/wifi.md for details of the authentication design.
*/
let OOBCert = Authenticators.OOBCert = {};
OOBCert.mode = "OOB_CERT";
OOBCert.Client = function() {};
OOBCert.Client.prototype = {
mode: OOBCert.mode,
};
OOBCert.Server = function() {};
OOBCert.Server.prototype = {
mode: OOBCert.mode,
/**
* Verify that listener settings are appropriate for this authentication mode.
*
* @param listener SocketListener
* The socket listener about to be opened.
* @throws if validation requirements are not met
*/
validateOptions(listener) {
if (!listener.encryption) {
throw new Error(OOBCert.mode + " authentication requires encryption.");
}
},
/**
* Augment the service discovery advertisement with any additional data needed
* to support this authentication mode.
*
* @param listener SocketListener
* The socket listener that was just opened.
* @param advertisement object
* The advertisement being built.
*/
augmentAdvertisement(listener, advertisement) {
advertisement.authentication = OOBCert.mode;
// Step A.4
// Server announces itself via service discovery
// Announcement contains hash(ServerCert) as additional data
advertisement.cert = {
sha256: listener._socket.serverCert.sha256Fingerprint
};
},
};
exports.Authenticators = {
get(mode) {
if (!mode) {
mode = Prompt.mode;
}
for (let key in Authenticators) {
let auth = Authenticators[key];
if (auth.mode === mode) {
return auth;
}
}
throw new Error("Unknown authenticator mode: " + mode);
}
};