Comparing version 0.17.1 to 0.17.2
@@ -34,3 +34,4 @@ // Copyright 2013 SAP AG. | ||
if (options.user && options.password) { | ||
this._authMethods.push(new SCRAMSHA256(options)); | ||
this._authMethods.push(new SCRAMSHA256(options, true)); // with PBKDF2 | ||
this._authMethods.push(new SCRAMSHA256(options, false)); // no PBKDF2 | ||
} | ||
@@ -68,3 +69,5 @@ if (!this._authMethods.length) { | ||
Manager.prototype.initialize = function initialize(fields) { | ||
Manager.prototype.initialize = function initialize(fields, cb) { | ||
var self = this; | ||
var uninitializedMethods = []; | ||
var initializedMethods = []; | ||
@@ -77,11 +80,21 @@ var name, method, buffer; | ||
if (method && buffer) { | ||
method.initialize(buffer); | ||
initializedMethods.push(method); | ||
uninitializedMethods.push([method, buffer]); | ||
} | ||
} | ||
if (!initializedMethods.length) { | ||
throw noAuthMethodFound(); | ||
if (uninitializedMethods.length === 0) { | ||
cb(noAuthMethodFound()); | ||
} | ||
this._authMethod = initializedMethods.shift(); | ||
this._authMethods = undefined; | ||
uninitializedMethods.forEach(function(pair) { | ||
method = pair[0]; | ||
buffer = pair[1] | ||
method.initialize(buffer, function(err) { | ||
if (err) return cb(err); | ||
initializedMethods.push(method); | ||
if (initializedMethods.length == uninitializedMethods.length) { // done | ||
self._authMethod = initializedMethods.shift(); | ||
self._authMethods = undefined; | ||
cb(); | ||
} | ||
}); | ||
}); | ||
}; | ||
@@ -123,2 +136,2 @@ | ||
return error; | ||
} | ||
} |
@@ -29,4 +29,5 @@ // Copyright 2013 SAP AG. | ||
SAML.prototype.initialize = function initialize(buffer) { | ||
SAML.prototype.initialize = function initialize(buffer, cb) { | ||
this.user = buffer.toString('utf8'); | ||
cb(); | ||
}; | ||
@@ -40,2 +41,2 @@ | ||
this.sessionCookie = buffer; | ||
}; | ||
}; |
@@ -21,2 +21,3 @@ // Copyright 2013 SAP AG. | ||
var CLIENT_PROOF_SIZE = 32; | ||
var SERVER_PROOF_SIZE = 32; | ||
var CLIENT_CHALLENGE_SIZE = 64; | ||
@@ -30,4 +31,9 @@ | ||
function SCRAMSHA256(options) { | ||
this.name = 'SCRAMSHA256'; | ||
function SCRAMSHA256(options, usePBKDF2) { | ||
this.usePBKDF2 = usePBKDF2; | ||
if (usePBKDF2) { | ||
this.name = 'SCRAMPBKDF2SHA256'; | ||
} else { | ||
this.name = 'SCRAMSHA256'; | ||
} | ||
this.password = options.password; | ||
@@ -39,2 +45,3 @@ if (util.isString(this.password)) { | ||
this.clientProof = undefined; | ||
this.serverProof = undefined; | ||
} | ||
@@ -46,3 +53,4 @@ | ||
SCRAMSHA256.prototype.initialize = function initialize(buffer) { | ||
SCRAMSHA256.prototype.initialize = function initialize(buffer, cb) { | ||
var self = this; | ||
var serverChallengeData = Fields.read({ | ||
@@ -52,4 +60,23 @@ argumentCount: 1, | ||
}); | ||
this.clientProof = calculateClientProof([serverChallengeData[0]], | ||
serverChallengeData[1], this.clientChallenge, this.password); | ||
if (this.usePBKDF2) { | ||
var iterations = serverChallengeData[2].readUInt32BE(); | ||
} else { | ||
var iterations = 0; | ||
} | ||
calculateProofs( | ||
[serverChallengeData[0]], | ||
serverChallengeData[1], | ||
this.clientChallenge, | ||
this.password, | ||
iterations, | ||
this.usePBKDF2, | ||
function(err, proofs) { | ||
if (err) { | ||
cb(err); | ||
return; | ||
} | ||
self.clientProof = proofs["CLIENT_PROOF"]; | ||
if (self.usePBKDF2) self.serverProof = proofs["SERVER_PROOF"]; | ||
cb(); | ||
}); | ||
}; | ||
@@ -63,22 +90,70 @@ | ||
/* jshint unused:false */ | ||
if (!this.usePBKDF2) return; | ||
var x = Buffer.compare(buffer, this.serverProof); | ||
if(x != 0) { | ||
var err = new Error("Server couldn't be authenticated"); | ||
err.code = 'EHDBSERVERAUTH'; | ||
throw err; | ||
} | ||
}; | ||
function calculateClientProof(salts, serverKey, clientKey, password) { | ||
var buf = new Buffer(2 + (CLIENT_PROOF_SIZE + 1) * salts.length); | ||
buf[0] = 0x00; | ||
buf.writeInt8(salts.length, 1); | ||
var offset = 2; | ||
salts.forEach(function scrambleSalt(salt) { | ||
buf.writeInt8(CLIENT_PROOF_SIZE, offset); | ||
offset += 1; | ||
scramble(salt, serverKey, clientKey, password).copy(buf, offset); | ||
offset += CLIENT_PROOF_SIZE; | ||
}); | ||
return buf; | ||
function calculateProofs(salts, serverKey, clientKey, password, iterations, usePBKDF2, cb) { | ||
var proofs = {}; | ||
var clientProof = new Buffer(2 + (CLIENT_PROOF_SIZE + 1) * salts.length); | ||
proofs["CLIENT_PROOF"] = clientProof; | ||
clientProof.writeUInt16BE(salts.length, 0); // sub-arg count BIG endian | ||
var cp_offset = 2; | ||
if (usePBKDF2) { | ||
var serverProof = new Buffer(2 + (SERVER_PROOF_SIZE + 1) * salts.length); | ||
proofs["SERVER_PROOF"] = serverProof; | ||
serverProof.writeUInt16LE(salts.length, 0); // sub-arg count LITTLE endian | ||
var sp_offset = 2; | ||
var pbkdf2Count = 0; | ||
salts.forEach(function(salt) { | ||
var length = salt.length + serverKey.length + clientKey.length; | ||
clientProof.writeInt8(CLIENT_PROOF_SIZE, cp_offset); | ||
cp_offset += 1; | ||
serverProof.writeInt8(SERVER_PROOF_SIZE, sp_offset); | ||
sp_offset += 1; | ||
var tmp_cp_offset = cp_offset; | ||
cp_offset += CLIENT_PROOF_SIZE; | ||
var tmp_sp_offset = sp_offset; | ||
sp_offset += SERVER_PROOF_SIZE; | ||
crypto.pbkdf2(password, | ||
salt, | ||
iterations, | ||
CLIENT_PROOF_SIZE, | ||
'sha256', | ||
function(err, salted_pwd) { | ||
++pbkdf2Count; | ||
scramble(salt, serverKey, clientKey, salted_pwd).copy(clientProof, tmp_cp_offset); | ||
var serverVerifier = hmac(salted_pwd, salt); | ||
var msg_server = Buffer.concat([clientKey, salt, serverKey], length); | ||
hmac(serverVerifier, msg_server).copy(serverProof, tmp_sp_offset); | ||
if (pbkdf2Count == salts.length) { // done | ||
cb(null, proofs); | ||
} | ||
}); | ||
}); | ||
} else { | ||
salts.forEach(function(salt) { | ||
clientProof.writeInt8(CLIENT_PROOF_SIZE, cp_offset); | ||
cp_offset += 1; | ||
var length = salt.length + serverKey.length + clientKey.length; | ||
var salted_pwd = hmac(password, salt); | ||
scramble(salt, serverKey, clientKey, salted_pwd).copy(clientProof, cp_offset); | ||
cp_offset += CLIENT_PROOF_SIZE; | ||
}); | ||
cb(null, proofs); | ||
} | ||
} | ||
function scramble(salt, serverKey, clientKey, password) { | ||
function scramble(salt, serverKey, clientKey, salted_pwd) { | ||
var length = salt.length + serverKey.length + clientKey.length; | ||
var msg = Buffer.concat([salt, serverKey, clientKey], length); | ||
var key = sha256(hmac(password, salt)); | ||
var key = sha256(salted_pwd); | ||
var sig = hmac(sha256(key), msg); | ||
@@ -107,2 +182,2 @@ return xor(sig, key); | ||
return new Buffer(hash.digest(), 'binary'); | ||
} | ||
} |
@@ -32,4 +32,5 @@ // Copyright 2013 SAP AG. | ||
SessionCookie.prototype.initialize = function initialize(buffer) { | ||
SessionCookie.prototype.initialize = function initialize(buffer, cb) { | ||
/* jshint unused:false */ | ||
cb(); | ||
}; | ||
@@ -43,2 +44,2 @@ | ||
/* jshint unused:false */ | ||
}; | ||
}; |
@@ -426,14 +426,13 @@ // Copyright 2013 SAP AG. | ||
} | ||
try { | ||
manager.initialize(reply.authentication); | ||
} catch (err) { | ||
return cb(err); | ||
} | ||
self.send(request.connect({ | ||
authentication: manager.finalData(), | ||
clientId: self.clientId, | ||
connectOptions: self.connectOptions.getOptions(), | ||
useCesu8: self.useCesu8 | ||
}), connReceive); | ||
manager.initialize(reply.authentication, function(err) { | ||
if (err) return cb(err); | ||
self.send(request.connect({ | ||
authentication: manager.finalData(), | ||
clientId: self.clientId, | ||
connectOptions: self.connectOptions.getOptions(), | ||
useCesu8: self.useCesu8 | ||
}), connReceive); | ||
}); | ||
} | ||
this.send(request.authenticate({ | ||
@@ -440,0 +439,0 @@ authentication: manager.initialData(), |
@@ -9,3 +9,3 @@ { | ||
"description": "SAP HANA Database Client for Node", | ||
"version": "0.17.1", | ||
"version": "0.17.2", | ||
"repository": { | ||
@@ -12,0 +12,0 @@ "type": "git", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
290635
8123