|
|
@ -16,7 +16,7 @@ const tlsOptions = {
|
|
|
|
const secureContext = createSecureContext(tlsOptions);
|
|
|
|
const secureContext = createSecureContext(tlsOptions);
|
|
|
|
export const openTLSSockets = new NodeCache({ useClones: false, stdTTL: 3600 }); // keep sockets for about one hour
|
|
|
|
export const openTLSSockets = new NodeCache({ useClones: false, stdTTL: 3600 }); // keep sockets for about one hour
|
|
|
|
|
|
|
|
|
|
|
|
export function startTLSServer(): events.EventEmitter {
|
|
|
|
export function startTLSServer(): { events: events.EventEmitter; tls: tls.TLSSocket } {
|
|
|
|
const duplexpair = new DuplexPair();
|
|
|
|
const duplexpair = new DuplexPair();
|
|
|
|
const emitter = new events.EventEmitter();
|
|
|
|
const emitter = new events.EventEmitter();
|
|
|
|
|
|
|
|
|
|
|
@ -58,7 +58,7 @@ export function startTLSServer(): events.EventEmitter {
|
|
|
|
emitter.emit('incoming', data);
|
|
|
|
emitter.emit('incoming', data);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
cleartext.once('close', (data: Buffer) => {
|
|
|
|
cleartext.once('close', (_data: Buffer) => {
|
|
|
|
console.log('cleartext close');
|
|
|
|
console.log('cleartext close');
|
|
|
|
emitter.emit('end');
|
|
|
|
emitter.emit('end');
|
|
|
|
});
|
|
|
|
});
|
|
|
@ -82,7 +82,10 @@ export function startTLSServer(): events.EventEmitter {
|
|
|
|
emitter.emit('end');
|
|
|
|
emitter.emit('end');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
return emitter;
|
|
|
|
return {
|
|
|
|
|
|
|
|
events: emitter,
|
|
|
|
|
|
|
|
tls: cleartext
|
|
|
|
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function md5Hex(buffer: Buffer): Buffer {
|
|
|
|
function md5Hex(buffer: Buffer): Buffer {
|
|
|
@ -91,18 +94,15 @@ function md5Hex(buffer: Buffer): Buffer {
|
|
|
|
return hasher.digest(); // new Buffer(hasher.digest("binary"), "binary");
|
|
|
|
return hasher.digest(); // new Buffer(hasher.digest("binary"), "binary");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function encodeTunnelPW(key: Buffer, authenticator: Buffer, secret: string): Buffer {
|
|
|
|
// alloc_size
|
|
|
|
// see freeradius TTLS implementation how to obtain "key"......
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// key should be:
|
|
|
|
|
|
|
|
// https://www.openssl.org/docs/man1.0.2/man3/SSL_export_keying_material.html
|
|
|
|
|
|
|
|
// https://github.com/nodejs/ffi/blob/master/deps/openssl/openssl/doc/man3/SSL_export_keying_material.pod
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// but not available in NODE JS
|
|
|
|
// 0,
|
|
|
|
|
|
|
|
// EAP_TLS_KEY_LEN 64
|
|
|
|
|
|
|
|
// EAP_EMSK_LEN 64
|
|
|
|
|
|
|
|
// const buffer = tlsSocket.exportKeyingMaterial(128, 'ttls keying material');
|
|
|
|
|
|
|
|
|
|
|
|
console.log('KEY', key);
|
|
|
|
export function encodeTunnelPW(key: Buffer, authenticator: Buffer, secret: string): Buffer {
|
|
|
|
console.log('authenticator', authenticator);
|
|
|
|
// see freeradius TTLS implementation how to obtain "key"......
|
|
|
|
console.log('secret', secret);
|
|
|
|
|
|
|
|
// https://tools.ietf.org/html/rfc2548
|
|
|
|
// https://tools.ietf.org/html/rfc2548
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -120,9 +120,6 @@ export function encodeTunnelPW(key: Buffer, authenticator: Buffer, secret: strin
|
|
|
|
Buffer.from(makeid(1))
|
|
|
|
Buffer.from(makeid(1))
|
|
|
|
]);
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
|
|
console.log('salt', salt);
|
|
|
|
|
|
|
|
// ensure left most bit is set to 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
String
|
|
|
|
String
|
|
|
|
The plaintext String field consists of three logical sub-fields:
|
|
|
|
The plaintext String field consists of three logical sub-fields:
|
|
|
@ -143,14 +140,13 @@ export function encodeTunnelPW(key: Buffer, authenticator: Buffer, secret: strin
|
|
|
|
used for padding. Call this plaintext P.
|
|
|
|
used for padding. Call this plaintext P.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
console.log('key', key.length, key);
|
|
|
|
|
|
|
|
let P = Buffer.concat([new Uint8Array([key.length]), key]); // + key + padding;
|
|
|
|
let P = Buffer.concat([new Uint8Array([key.length]), key]); // + key + padding;
|
|
|
|
|
|
|
|
|
|
|
|
// fill up with 0x00 till we have % 16
|
|
|
|
// fill up with 0x00 till we have % 16
|
|
|
|
while (P.length % 16 !== 0) {
|
|
|
|
while (P.length % 16 !== 0) {
|
|
|
|
P = Buffer.concat([P, Buffer.from([0x00])]);
|
|
|
|
P = Buffer.concat([P, Buffer.from([0x00])]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// console.log('PLAINTEXT', P.length, P);
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
Call the shared secret S, the pseudo-random 128-bit Request
|
|
|
|
Call the shared secret S, the pseudo-random 128-bit Request
|
|
|
|
Authenticator (from the corresponding Access-Request packet) R,
|
|
|
|
Authenticator (from the corresponding Access-Request packet) R,
|
|
|
@ -160,6 +156,21 @@ export function encodeTunnelPW(key: Buffer, authenticator: Buffer, secret: strin
|
|
|
|
Intermediate values b(1), b(2)...c(i) are required. Encryption
|
|
|
|
Intermediate values b(1), b(2)...c(i) are required. Encryption
|
|
|
|
is performed in the following manner ('+' indicates
|
|
|
|
is performed in the following manner ('+' indicates
|
|
|
|
concatenation):
|
|
|
|
concatenation):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Zorn Informational [Page 21]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RFC 2548 Microsoft Vendor-specific RADIUS Attributes March 1999
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
b(1) = MD5(S + R + A) c(1) = p(1) xor b(1) C = c(1)
|
|
|
|
|
|
|
|
b(2) = MD5(S + c(1)) c(2) = p(2) xor b(2) C = C + c(2)
|
|
|
|
|
|
|
|
. .
|
|
|
|
|
|
|
|
. .
|
|
|
|
|
|
|
|
. .
|
|
|
|
|
|
|
|
b(i) = MD5(S + c(i-1)) c(i) = p(i) xor b(i) C = C + c(i)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The resulting encrypted String field will contain
|
|
|
|
|
|
|
|
c(1)+c(2)+...+c(i).
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
const p: Buffer[] = [];
|
|
|
|
const p: Buffer[] = [];
|
|
|
@ -171,20 +182,11 @@ export function encodeTunnelPW(key: Buffer, authenticator: Buffer, secret: strin
|
|
|
|
const R = authenticator;
|
|
|
|
const R = authenticator;
|
|
|
|
const A = salt;
|
|
|
|
const A = salt;
|
|
|
|
|
|
|
|
|
|
|
|
// console.log('S', S);
|
|
|
|
|
|
|
|
// console.log('R', R);
|
|
|
|
|
|
|
|
// console.log('A', A);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// const P = Buffer.alloc(16);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let C;
|
|
|
|
let C;
|
|
|
|
const c: { [key: number]: Buffer } = {};
|
|
|
|
const c: { [key: number]: Buffer } = {};
|
|
|
|
const b: { [key: number]: Buffer } = {};
|
|
|
|
const b: { [key: number]: Buffer } = {};
|
|
|
|
|
|
|
|
|
|
|
|
// console.log('S + R + A', S + R + A);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < p.length; i++) {
|
|
|
|
for (let i = 0; i < p.length; i++) {
|
|
|
|
// one octet is 8.. therefore +=2 means next 16
|
|
|
|
|
|
|
|
if (!i) {
|
|
|
|
if (!i) {
|
|
|
|
b[i] = md5Hex(Buffer.concat([Buffer.from(S), R, A]));
|
|
|
|
b[i] = md5Hex(Buffer.concat([Buffer.from(S), R, A]));
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
@ -197,29 +199,10 @@ export function encodeTunnelPW(key: Buffer, authenticator: Buffer, secret: strin
|
|
|
|
c[i][n] = p[i][n] ^ b[i][n];
|
|
|
|
c[i][n] = p[i][n] ^ b[i][n];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// console.log('c['+i+']', c[i]);
|
|
|
|
|
|
|
|
// console.log('b['+i+']', b[i]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
C = C ? Buffer.concat([C, c[i]]) : c[i];
|
|
|
|
C = C ? Buffer.concat([C, c[i]]) : c[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const bufferC = Buffer.from(C);
|
|
|
|
const bufferC = Buffer.from(C);
|
|
|
|
console.log('BUFFER C', bufferC.length, bufferC);
|
|
|
|
|
|
|
|
return Buffer.concat([salt, bufferC]);
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
Zorn Informational [Page 21]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RFC 2548 Microsoft Vendor-specific RADIUS Attributes March 1999
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
b(1) = MD5(S + R + A) c(1) = p(1) xor b(1) C = c(1)
|
|
|
|
|
|
|
|
b(2) = MD5(S + c(1)) c(2) = p(2) xor b(2) C = C + c(2)
|
|
|
|
|
|
|
|
. .
|
|
|
|
|
|
|
|
. .
|
|
|
|
|
|
|
|
. .
|
|
|
|
|
|
|
|
b(i) = MD5(S + c(i-1)) c(i) = p(i) xor b(i) C = C + c(i)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The resulting encrypted String field will contain
|
|
|
|
return Buffer.concat([salt, bufferC]);
|
|
|
|
c(1)+c(2)+...+c(i).
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|