Permalink
Browse files

add first cut (#301)

WAMP-cryptosign support
  • Loading branch information...
oberstet committed May 23, 2017
1 parent c306584 commit 37fb3232ff0842c166ef1d86265602d2b1292d26
Showing with 376 additions and 3 deletions.
  1. +6 −0 doc/changelog.md
  2. +158 −0 lib/auth/cryptosign.js
  3. +4 −0 lib/autobahn.js
  4. +1 −1 lib/session.js
  5. +70 −1 lib/util.js
  6. +1 −1 package.json
  7. +136 −0 test/test_cryptosign.html
View
@@ -1,5 +1,11 @@
# AutobahnJS - Change Log
## v17.5.2
* new: WAMP-cryptosign authentication support
---
## v0.9.1
* compatibility with latest WAMP v2 spec ("RC-2, 2014/02/22")
View
@@ -0,0 +1,158 @@
///////////////////////////////////////////////////////////////////////////////
//
// AutobahnJS - http://autobahn.ws, http://wamp.ws
//
// A JavaScript library for WAMP ("The Web Application Messaging Protocol").
//
// Copyright (c) Crossbar.io Technologies GmbH and contributors
//
// Licensed under the MIT License.
// http://www.opensource.org/licenses/mit-license.php
//
///////////////////////////////////////////////////////////////////////////////
var nacl = require('tweetnacl');
var util = require('../util.js');
var log = require('../log.js');
var connection = require('../connection.js');
function load_private_key (name, force_regenerate) {
var seed = util.atob(localStorage.getItem(name));
if (!seed || force_regenerate) {
seed = nacl.randomBytes(nacl.sign.seedLength);
localStorage.setItem(name, util.btoa(seed));
log.debug('new key seed "' + name + '" saved to local storage!');
} else {
log.debug('key seed "' + name + '" loaded from local storage!');
}
return nacl.sign.keyPair.fromSeed(seed);
}
exports.load_private_key = load_private_key;
function delete_private_key (name) {
// FIXME: poor man's secure erase
for (var i = 0; i < 5; ++i) {
seed = nacl.randomBytes(nacl.sign.seedLength);
localStorage.setItem(name, util.btoa(seed));
localStorage.setItem(name, '');
localStorage.setItem(name, null);
}
}
exports.delete_private_key = delete_private_key;
function sign_challenge (pkey, extra) {
var challenge = util.htob(extra.challenge);
var signature = nacl.sign.detached(challenge, pkey.secretKey);
var res = util.btoh(signature) + util.btoh(challenge);
return res;
}
exports.sign_challenge = sign_challenge;
function public_key (pkey) {
return util.btoh(pkey.publicKey);
}
exports.public_key = public_key;
function create_connection (config) {
var url = config.url;
var realm = config.realm;
var authid = config.authid;
var pkey = config.pkey;
var activation_code = config.activation_code;
var request_new_activation_code = config.request_new_activation_code;
var serializers = config.serializers;
if (config.debug) {
console.log(url);
console.log(realm);
console.log(authid);
console.log(pkey);
console.log(activation_code);
console.log(request_new_activation_code);
console.log(serializers);
}
function onchallenge (session, method, extra) {
// we only know how to process WAMP-cryptosign here!
if (method == "cryptosign") {
// and to do so, we let above helper sign the
// WAMP-cryptosign challenge as required
// and return a signature
return sign_challenge(pkey, extra);
} else {
throw "don't know how to authenticate using '" + method + "'";
}
}
authextra = {
// forward the client pubkey: this allows us to omit authid as
// the router can identify us with the pubkey already
pubkey: public_key(pkey),
// not yet implemented. a public key the router should provide
// a trustchain for it's public key. the trustroot can eg be
// hard-coded in the client, or come from a command line option.
trustroot: null,
// not yet implemented. for authenticating the router, this
// challenge will need to be signed by the router and send back
// in AUTHENTICATE for client to verify. A string with a hex
// encoded 32 bytes random value.
challenge: null,
// FIXME: at least on NodeJS, it should be possible to implement
// this additional security measure!
//channel_binding: 'tls-unique'
channel_binding: null,
// you should only provide an activation_code the very first time
// the key pair used is paired. a token can only be used exactly once
// and reusing it, even from the original client, will result in an error!
activation_code: activation_code,
// if true, request sending a new email with a new activation code
request_new_activation_code: request_new_activation_code
}
// now create a AutobahnJS Connection object
// with WAMP-cryptosign being the only configured
// authentication method:
var _connection = new connection.Connection({
// this MUST be given
url: url,
// this MAY be given - if not, then connect to global user realm
// if given, the user must have access permissions for the respective
// management realm (to which both users and fabric nodes are connected)
realm: realm,
// this MAY be given (but MUST be given on register/pairing)
authid: authid,
// this MUST be given
authmethods: ["cryptosign"],
// see above
onchallenge: onchallenge,
// see above
authextra: authextra,
// WAMP serializers to use
serializers: config.serializers
});
return _connection;
}
exports.create_connection = create_connection;
View
@@ -21,6 +21,7 @@ var when = require('when');
var msgpack = require('msgpack-lite');
var cbor = require('cbor');
var nacl = require('tweetnacl');
if ('AUTOBAHN_DEBUG' in global && AUTOBAHN_DEBUG) {
// https://github.com/cujojs/when/blob/master/docs/api.md#whenmonitor
@@ -39,6 +40,7 @@ var serializer = require('./serializer.js');
var persona = require('./auth/persona.js');
var cra = require('./auth/cra.js');
var cryptosign = require('./auth/cryptosign.js');
exports.version = pjson.version;
@@ -59,10 +61,12 @@ exports.serializer = serializer;
exports.auth_persona = persona.auth;
exports.auth_cra = cra;
exports.auth_cryptosign = cryptosign;
exports.when = when;
exports.msgpack = msgpack;
exports.cbor = cbor;
exports.nacl = nacl;
exports.util = util;
exports.log = log;
View
@@ -1126,7 +1126,7 @@ Session.prototype.log = function () {
Session.prototype.join = function (realm, authmethods, authid, authextra) {
util.assert(typeof realm === 'string', "Session.join: <realm> must be a string");
util.assert(!realm || typeof realm === 'string', "Session.join: <realm> must be a string");
util.assert(!authmethods || Array.isArray(authmethods), "Session.join: <authmethods> must be an array []");
util.assert(!authid || typeof authid === 'string', "Session.join: <authid> must be a string");
View
@@ -17,6 +17,76 @@ var when = require('when');
function _base64_to_uint8array (input) {
var raw = new Buffer(input, 'base64');
var arr = new Uint8Array(new ArrayBuffer(raw.length));
for(i = 0; i < raw.length; i++) {
arr[i] = raw[i];
}
return arr;
};
exports.base64_to_uint8array = _base64_to_uint8array;
function _string_to_uint8array (str) {
var raw = new Buffer(str, 'utf8');
var arr = new Uint8Array(new ArrayBuffer(raw.length));
for(i = 0; i < raw.length; i++) {
arr[i] = raw[i];
}
return arr;
};
exports.string_to_uint8array = _string_to_uint8array
function _atob (s) {
return new Uint8Array(atob(s).split("").map(function(c) { return c.charCodeAt(0); }));
}
exports.atob = _atob
function _btoa (b) {
return btoa(String.fromCharCode.apply(null, b));
}
exports.btoa = _btoa
function _btoh (bytes) {
var res = '';
for (var i = 0; i < bytes.length; ++i) {
res += ('0' + (bytes[i] & 0xFF).toString(16)).slice(-2);
}
return res;
}
exports.btoh = _btoh
function _htob (hex) {
if (typeof hex !== 'string') {
throw new TypeError('Expected input to be a string')
}
if ((hex.length % 2) !== 0) {
throw new RangeError('Expected string to be an even number of characters')
}
var view = new Uint8Array(hex.length / 2)
for (var i = 0; i < hex.length; i += 2) {
view[i / 2] = parseInt(hex.substring(i, i + 2), 16)
}
return view
}
exports.htob = _htob
var rand_normal = function (mean, sd) {
// Derive a Gaussian from Uniform random variables
// http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform
@@ -200,7 +270,6 @@ var defaults = function () {
};
exports.rand_normal = rand_normal;
exports.assert = assert;
exports.http_post = http_post;
View
@@ -1,6 +1,6 @@
{
"name": "autobahn",
"version": "17.5.1",
"version": "17.5.2",
"description": "An implementation of The Web Application Messaging Protocol (WAMP).",
"main": "index.js",
"scripts": {
Oops, something went wrong.

0 comments on commit 37fb323

Please sign in to comment.