diff --git a/lib/verifier/certassertion.js b/lib/verifier/certassertion.js index ac94d2ee659cfdf8879e125e9f70e7714563f242..12fd622dd3de338232b81acee8237033dc0ea543 100644 --- a/lib/verifier/certassertion.js +++ b/lib/verifier/certassertion.js @@ -37,7 +37,7 @@ // // rewritten idassertion for certificates -const xml2js = require("xml2js/lib/xml2js"), +const http = require("http"), https = require("https"), url = require("url"), @@ -49,95 +49,15 @@ config = require("../configuration.js"), logger = require("../logging.js").logger, secrets = require('../secrets.js'); -const HOSTMETA_URL = "/.well-known/host-meta"; - -var publicKeys = {}; - try { const publicKey = secrets.loadPublicKey(); + if (typeof publicKey !== 'object') throw "secrets.loadPublicKey() returns non-object, load failure"; } catch(e){ logger.error("can't read public key, exiting: " + e); setTimeout(function() { process.exit(1); }, 0); } -publicKeys[config.get('hostname')] = publicKey; - -logger.debug("pre-seeded public key cache with key for " + - config.get('hostname')); - -function https_complete_get(host, url, successCB, errorCB) { - https.get({host: host,path: url}, function(res) { - var allData = ""; - res.on('data', function(d) { - allData += d; - }); - - res.on('end', function() { - successCB(allData); - }); - - }).on('error', function(e) { - logger.warn(e.toString()); - errorCB(e); - }); -} - -// only over SSL -function retrieveHostPublicKey(host, successCB, errorCB) { - logger.debug("attempting to fetching public key for " + host); - - // cached? - var cached = publicKeys[host]; - if (cached) { - logger.debug("public key for " + host + " returned from cache"); - return successCB(cached); - } - - logger.debug("performing HTTP request to fetch public key from " + host); - - https_complete_get(host, HOSTMETA_URL, function(hostmeta) { - // find the location of the public key - var parser = new xml2js.Parser(); - - parser.addListener('end', function(parsedDoc) { - // FIXME do we need to check hm:Host? - - var pk_location = null; - - // get the public key location - var links = parsedDoc["Link"]; - if (links instanceof Array) { - for (var i in links) { - var link = links[i]; - var rel = link["@"]["rel"]; - if (rel) { - if (rel.toLowerCase() == "https://browserid.org/vocab#publicKey") { - pk_location = link["@"]["href"]; - break; - } - } - } - } - - // if we don't have a pk - if (!pk_location) - return errorCB("no public key in host-meta"); - - // go fetch the public key - https_complete_get(host, pk_location, function(raw_pk) { - // parse the key - var pk = jwk.PublicKey.deserialize(raw_pk); - - // cache it - publicKeys[host] = pk; - - return successCB(pk); - }); - }); - - parser.parseString(hostmeta); - }, errorCB); -} +logger.debug("This verifier will accept assertions issued by " + config.get('hostname')); // compare two audiences: // *want* is what was extracted from the assertion (it's trusted, we @@ -198,31 +118,17 @@ function compareAudiences(want, got) { // // assertion is a bundle of the underlying assertion and the cert list // audience is a web origin, e.g. https://foo.com or http://foo.org:81 -// -// pkRetriever should be sent in only by code that really understands -// what it's doing, e.g. testing code. -function verify(assertion, audience, successCB, errorCB, pkRetriever) { +function verify(assertion, audience, successCB, errorCB) { // assertion is bundle var bundle = vep.unbundleCertsAndAssertion(assertion); - var theIssuer; jwcert.JWCert.verifyChain( bundle.certificates, new Date(), function(issuer, next) { - theIssuer = issuer; // allow other retrievers for testing - if (pkRetriever) - pkRetriever(issuer, next); - else - retrieveHostPublicKey(issuer, next, function(err) {next(null);}); + if (issuer === config.get('hostname')) return next(publicKey); + return errorCB("this verifier doesn't respect certs issued from domains other than: " + config.get('hostname')); }, function(pk, principal) { - // primary? - if (theIssuer != config.get('hostname')) { - // then the email better match the issuer - if (!principal.email.match("@" + theIssuer + "$")) - return errorCB(); - } - var tok = new jwt.JWT(); tok.parse(bundle.assertion); @@ -235,13 +141,11 @@ function verify(assertion, audience, successCB, errorCB, pkRetriever) { } if (tok.verify(pk)) { - successCB(principal.email, tok.audience, tok.expires, theIssuer); + successCB(principal.email, tok.audience, tok.expires, config.get('hostname')); } else { - errorCB(); + errorCB("verification failure"); } }, errorCB); -} - +}; -exports.retrieveHostPublicKey = retrieveHostPublicKey; exports.verify = verify;