fix: a lot of bug fixes, first running version for windows and android :)

code is super ugly right now.. please don't judge
This commit is contained in:
simon 2020-02-22 02:32:12 +01:00
parent 7e28c60d81
commit 4989c2b6bc
21 changed files with 449 additions and 97 deletions

33
config.js Normal file
View File

@ -0,0 +1,33 @@
import * as fs from 'fs';
module.exports = {
// radius secret
secret: 'testing123',
certificate: {
cert: fs.readFileSync('./ssl/cert/server.crt'),
key: [
{
pem: fs.readFileSync('./ssl/cert/server.key') as Buffer,
passphrase: 'whatever2020'
}
]
},
// authentication
authentication: 'ldap',
authenticationOptions: {
url: 'ldap://127.0.0.1:1636',
base: 'dc=hokify,dc=com',
tlsOptions2: {
key: fs.readFileSync('ldap.gsuite.hokify.com.40567.key'),
cert: fs.readFileSync('ldap.gsuite.hokify.com.40567.crt'),
// This is necessary only if using the client certificate authentication.
requestCert: true,
// This is necessary only if the client uses the self-signed certificate.
ca: [fs.readFileSync('ldap.gsuite.hokify.com.40567.key')]
}
}
};

View File

@ -3,7 +3,7 @@
"description": "radius server for google LDAP and TTLT", "description": "radius server for google LDAP and TTLT",
"version": "0.0.1", "version": "0.0.1",
"scripts": { "scripts": {
"start": "node dist/app.js", "start": "/home/simon/Dev/others/node/node dist/app.js",
"build": "tsc", "build": "tsc",
"dev": "ts-node src/app.ts", "dev": "ts-node src/app.ts",
"test-ttls-pap": "eapol_test -c ./ttls-pap.conf -s testing123", "test-ttls-pap": "eapol_test -c ./ttls-pap.conf -s testing123",
@ -17,7 +17,8 @@
"ts-node": "^8.6.2", "ts-node": "^8.6.2",
"type-cacheable": "^4.0.0", "type-cacheable": "^4.0.0",
"yargs": "~15.1.0", "yargs": "~15.1.0",
"md5": "^2.2.1" "md5": "^2.2.1",
"passport-ldapauth": "^2.1.3"
}, },
"devDependencies": { "devDependencies": {
"@types/ldapjs": "^1.0.5", "@types/ldapjs": "^1.0.5",

View File

@ -3,27 +3,15 @@ import * as radius from 'radius';
// import * as dgram from "dgram"; // import * as dgram from "dgram";
// import * as fs from 'fs'; // import * as fs from 'fs';
import { EAPHandler } from './eap'; import { EAPHandler } from './eap';
import { makeid } from './helpers'; import { IDeferredPromise, makeid, MAX_RADIUS_ATTRIBUTE_SIZE, newDeferredPromise } from './helpers';
import { LDAPAuth } from './ldap'; import { GoogleLDAPAuth } from './auth/google-ldap';
import { AdditionalAuthHandler } from './types/Handler'; import { AdditionalAuthHandler } from './types/Handler';
const server = dgram.createSocket('udp4'); const server = dgram.createSocket('udp4');
// not used right now, using stunnel to connect to ldap
/* const tlsOptions = {
key: fs.readFileSync('ldap.gsuite.hokify.com.40567.key'),
cert: fs.readFileSync('ldap.gsuite.hokify.com.40567.crt'),
// This is necessary only if using the client certificate authentication.
requestCert: true,
// This is necessary only if the client uses the self-signed certificate.
ca: [fs.readFileSync('ldap.gsuite.hokify.com.40567.key')]
}; */
const { argv } = require('yargs') const { argv } = require('yargs')
.usage('Simple Google LDAP <> RADIUS Server\nUsage: $0') .usage('RADIUS Server\nUsage: $0')
.example('$0 --port 1812 -s radiussecret') .example('$0 --port 1812 -s radiussecret')
.default({ .default({
port: 1812, port: 1812,
@ -46,9 +34,39 @@ console.log(`LDAP Server: ${argv.ldapServer}`);
// const ldap = new LDAPAuth({url: 'ldap://ldap.google.com', base: 'dc=hokify,dc=com', uid: 'uid', tlsOptions}); // const ldap = new LDAPAuth({url: 'ldap://ldap.google.com', base: 'dc=hokify,dc=com', uid: 'uid', tlsOptions});
const ldap = new LDAPAuth(argv.ldapServer, argv.baseDN); const ldap = new GoogleLDAPAuth(argv.ldapServer, argv.baseDN);
const eapHandler = new EAPHandler(); const eapHandler = new EAPHandler();
const timeout: { [key: string]: NodeJS.Timeout } = {};
const waitForNextMsg: { [key: string]: IDeferredPromise } = {};
function sendToClient(
msg: string | Uint8Array,
offset: number,
length: number,
port?: number,
address?: string,
callback?: (error: Error | null, bytes: number) => void,
stateForRetry?: string
): void {
let retried = 0;
function sendResponse() {
console.log(`sending response... (try: ${retried})`);
server.send(msg, offset, length, port, address, (error: Error | null, bytes: number) => {
// all good
if (callback) callback(error, bytes);
});
if (stateForRetry && retried < 3) {
// timeout[stateForRetry] = setTimeout(sendResponse, 600 * (retried+1));
}
retried++;
}
sendResponse();
}
server.on('message', async function(msg, rinfo) { server.on('message', async function(msg, rinfo) {
const packet = radius.decode({ packet: msg, secret: argv.secret }); const packet = radius.decode({ packet: msg, secret: argv.secret });
@ -57,7 +75,6 @@ server.on('message', async function(msg, rinfo) {
console.log('unknown packet type: ', packet.code); console.log('unknown packet type: ', packet.code);
return; return;
} }
// console.log('packet.attributes', packet.attributes); // console.log('packet.attributes', packet.attributes);
// console.log('rinfo', rinfo); // console.log('rinfo', rinfo);
@ -90,7 +107,7 @@ server.on('message', async function(msg, rinfo) {
}); });
console.log(`Sending ${success ? 'accept' : 'reject'} for user ${username}`); console.log(`Sending ${success ? 'accept' : 'reject'} for user ${username}`);
server.send(response, 0, response.length, rinfo.port, rinfo.address, function(err, _bytes) { sendToClient(response, 0, response.length, rinfo.port, rinfo.address, function(err, _bytes) {
if (err) { if (err) {
console.log('Error sending response to ', rinfo); console.log('Error sending response to ', rinfo);
} }
@ -99,15 +116,22 @@ server.on('message', async function(msg, rinfo) {
if (packet.attributes['EAP-Message']) { if (packet.attributes['EAP-Message']) {
const state = (packet.attributes.State && packet.attributes.State.toString()) || makeid(16); const state = (packet.attributes.State && packet.attributes.State.toString()) || makeid(16);
// EAP MESSAGE
eapHandler.handleEAPMessage(packet.attributes['EAP-Message'], state, { if (timeout[state]) {
clearTimeout(timeout[state]);
}
const handlers = {
response: (EAPMessage: Buffer) => { response: (EAPMessage: Buffer) => {
const attributes: any = [['State', Buffer.from(state)]]; const attributes: any = [['State', Buffer.from(state)]];
let sentDataSize = 0; let sentDataSize = 0;
do { do {
if (EAPMessage.length > 0) { if (EAPMessage.length > 0) {
attributes.push(['EAP-Message', EAPMessage.slice(sentDataSize, sentDataSize + 253)]); attributes.push([
sentDataSize += 253; 'EAP-Message',
EAPMessage.slice(sentDataSize, sentDataSize + MAX_RADIUS_ATTRIBUTE_SIZE)
]);
sentDataSize += MAX_RADIUS_ATTRIBUTE_SIZE;
} }
} while (sentDataSize < EAPMessage.length); } while (sentDataSize < EAPMessage.length);
@ -118,14 +142,34 @@ server.on('message', async function(msg, rinfo) {
attributes attributes
}); });
server.send(response, 0, response.length, rinfo.port, rinfo.address, function(err, _bytes) { waitForNextMsg[state] = newDeferredPromise();
sendToClient(
response,
0,
response.length,
rinfo.port,
rinfo.address,
function(err, _bytes) {
if (err) { if (err) {
console.log('Error sending response to ', rinfo); console.log('Error sending response to ', rinfo);
} }
}); },
state
);
return waitForNextMsg[state].promise;
}, },
checkAuth checkAuth
}); };
if (waitForNextMsg[state]) {
const identifier = packet.attributes['EAP-Message'].slice(1, 2).readUInt8(0); // .toString('hex');
waitForNextMsg[state].resolve({ response: handlers.response, identifier });
}
// EAP MESSAGE
eapHandler.handleEAPMessage(packet.attributes['EAP-Message'], state, handlers);
} else { } else {
const username = packet.attributes['User-Name']; const username = packet.attributes['User-Name'];
const password = packet.attributes['User-Password']; const password = packet.attributes['User-Password'];

View File

@ -1,13 +1,14 @@
import * as NodeCache from 'node-cache'; import * as NodeCache from 'node-cache';
import { createClient, Client } from 'ldapjs'; import { createClient, Client } from 'ldapjs';
import { IAuthentication } from '../types/Authentication';
const usernameFields = ['posixUid', 'mail']; const usernameFields = ['posixUid', 'mail'];
// TLS: // TLS:
// https://github.com/ldapjs/node-ldapjs/issues/307 // https://github.com/ldapjs/node-ldapjs/issues/307
export class LDAPAuth { export class GoogleLDAPAuth implements IAuthentication {
cache = new NodeCache(); cache = new NodeCache();
ldap: Client; ldap: Client;
@ -24,7 +25,7 @@ export class LDAPAuth {
this.fetchDNs(); this.fetchDNs();
} }
async fetchDNs() { private async fetchDNs() {
const dns: { [key: string]: string } = {}; const dns: { [key: string]: string } = {};
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
@ -119,6 +120,6 @@ export class LDAPAuth {
this.cache.set(cacheKey, true, 86400); this.cache.set(cacheKey, true, 86400);
return true; return username;
} }
} }

View File

@ -4,6 +4,7 @@
// https://tools.ietf.org/html/draft-funk-eap-ttls-v1-00 TTLS v1 (not implemented) // https://tools.ietf.org/html/draft-funk-eap-ttls-v1-00 TTLS v1 (not implemented)
import { IResponseHandlers, ResponseHandler } from './types/Handler'; import { IResponseHandlers, ResponseHandler } from './types/Handler';
import { EAPTTLS } from './eap/eap-ttls'; import { EAPTTLS } from './eap/eap-ttls';
import { MAX_RADIUS_ATTRIBUTE_SIZE } from './helpers';
export class EAPHandler { export class EAPHandler {
eapTTLS: EAPTTLS; eapTTLS: EAPTTLS;
@ -17,28 +18,35 @@ export class EAPHandler {
* @param data * @param data
* @param type 1 = identity, 21 = EAP-TTLS, 2 = notification, 4 = md5-challenge, 3 = NAK * @param type 1 = identity, 21 = EAP-TTLS, 2 = notification, 4 = md5-challenge, 3 = NAK
*/ */
private sendEAPResponse( private async sendEAPResponse(
response: ResponseHandler, response: ResponseHandler,
identifier: number, identifier: number,
data?: Buffer, data?: Buffer,
msgType = 21, msgType = 21,
msgFlags = 0x00 msgFlags = 0x00
) { ) {
const maxFragmentSize = 1400; // @todo .. take framed-mtu into account from AVPs
let i = 0; let i = 0;
const maxSize = (MAX_RADIUS_ATTRIBUTE_SIZE - 5) * 4;
let sentDataSize = 0;
let currentIdentifier = identifier;
let currentResponse = response;
do { do {
const fragmentMaxPart = // SLICE
data && (i + 1) * maxFragmentSize > data.length ? undefined : (i + 1) * maxFragmentSize;
const sslPart = data && data.slice(i * maxFragmentSize, fragmentMaxPart);
console.log('sslPart', sslPart, i, maxFragmentSize, i * maxFragmentSize, fragmentMaxPart);
const includeLength = // const fragmentMaxPart =
data && // data && (i + 1) * maxFragmentSize > data.length ? (i + 1) * maxFragmentSize : undefined;
i === 0 &&
fragmentMaxPart !== undefined; /* firsrt one and we have more, therefore include length */ const dataPart = data && data.length > 0 && data.slice(sentDataSize, sentDataSize + maxSize);
/* it's the first one and we have more, therefore include length */
const includeLength = data && i === 0 && sentDataSize < data.length;
sentDataSize += maxSize;
// console.log('includeLength', includeLength, fragmentMaxPart, i)
i += 1; i += 1;
/* /*
@ -62,11 +70,13 @@ export class EAPHandler {
const flags = const flags =
msgFlags + msgFlags +
(includeLength ? 0b10000000 : 0) + // set L bit (includeLength ? 0b10000000 : 0) + // set L bit
(fragmentMaxPart /* we have more */ ? 0b01000000 : 0); // set M bit (data && sentDataSize < data.length /* we have more */ ? 0b01000000 : 0); // set M bit
currentIdentifier++;
let buffer = Buffer.from([ let buffer = Buffer.from([
1, // request 1, // request
identifier + 1, currentIdentifier,
0, // length (1/2) 0, // length (1/2)
0, // length (2/2) 0, // length (2/2)
msgType, // 1 = identity, 21 = EAP-TTLS, 2 = notificaiton, 4 = md5-challenge, 3 = NAK msgType, // 1 = identity, 21 = EAP-TTLS, 2 = notificaiton, 4 = md5-challenge, 3 = NAK
@ -81,15 +91,16 @@ export class EAPHandler {
buffer = Buffer.concat([buffer, length]); buffer = Buffer.concat([buffer, length]);
} }
const resBuffer = sslPart ? Buffer.concat([buffer, sslPart]) : buffer; const resBuffer = dataPart ? Buffer.concat([buffer, dataPart]) : buffer;
resBuffer.writeUInt16BE(resBuffer.byteLength, 2); resBuffer.writeUInt16BE(resBuffer.byteLength, 2);
console.log('EAP RESPONSE', { console.log('<<<<<<<<<<<< EAP RESPONSE TO CLIENT', {
code: 1, code: 1,
identifier: identifier + 1, currentIdentifier,
length: (includeLength && data && data.byteLength) || 0, includeLength,
msgType, length: (data && data.byteLength) || 0,
flags, msgType: msgType.toString(10),
flags: `00000000${flags.toString(2)}`.substr(-8),
data data
}); });
@ -98,13 +109,14 @@ export class EAPHandler {
// buffer.writeInt8(21, 4); // eap-ttls // buffer.writeInt8(21, 4); // eap-ttls
// buffer.writeInt8(0, 5); // flags // buffer.writeInt8(0, 5); // flags
/* console.log('sending message with identifier', currentIdentifier);
@todo: this is wrong, ({ identifier: currentIdentifier, response: currentResponse } = await currentResponse(
if there are more messages, add them to a queue resBuffer
and process the next one when client has ack. (message without data) ));
*/ console.log('next message got identifier', currentIdentifier);
response(resBuffer); } while (data && sentDataSize < data.length);
} while (data && i * maxFragmentSize < data.length);
console.log('DONE', sentDataSize, data && data.length);
} }
handleEAPMessage(msg: Buffer, state: string, handlers: IResponseHandlers) { handleEAPMessage(msg: Buffer, state: string, handlers: IResponseHandlers) {
@ -148,8 +160,7 @@ export class EAPHandler {
Message Length | Data... Message Length | Data...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/ */
console.log('>>>>>>>>>>>> REQUEST FROM CLIENT: IDENTIFY', {});
console.log('RESPONDING WITH IDENTIDY / START');
this.sendEAPResponse(handlers.response, identifier, undefined, 21, 0x20); this.sendEAPResponse(handlers.response, identifier, undefined, 21, 0x20);
@ -167,14 +178,17 @@ export class EAPHandler {
break; break;
case 21: // EAP TTLS case 21: // EAP TTLS
this.eapTTLS.handleMessage(msg, state, handlers, identifier); this.eapTTLS.handleMessage(msg, state, handlers, identifier);
return; break;
case 3: // nak case 3: // nak
this.sendEAPResponse(handlers.response, identifier, undefined, 3); // this.sendEAPResponse(handlers.response, identifier, undefined, 3);
break; break;
case 2: // notification case 2: // notification
console.log('>>>>>>>>>>>> REQUEST FROM CLIENT: notification', {});
console.info('notification'); console.info('notification');
break; break;
case 4: // md5-challenge case 4: // md5-challenge
console.log('>>>>>>>>>>>> REQUEST FROM CLIENT: md5-challenge', {});
console.info('md5-challenge'); console.info('md5-challenge');
break; break;
case 254: // expanded type case 254: // expanded type
@ -183,7 +197,11 @@ export class EAPHandler {
break; break;
default: default:
console.error('unsupported type', type); // we do not support this auth type, ask for TTLS
console.error('unsupported type', type, 'requesting TTLS (21)');
this.sendEAPResponse(handlers.response, identifier, Buffer.from([21]), 3);
break; break;
} }
break; break;

View File

@ -1,6 +1,6 @@
import { IAuthChallenge } from '../../types/AuthChallenge'; import { IEAPChallenge } from '../../types/EAPChallenge';
export class PAPChallenge implements IAuthChallenge { export class PAPChallenge implements IEAPChallenge {
// i couldn't find any documentation about it, therefore best guess how this is processed... // i couldn't find any documentation about it, therefore best guess how this is processed...
// http://www.networksorcery.com/enp/rfc/rfc1334.txt ? // http://www.networksorcery.com/enp/rfc/rfc1334.txt ?

View File

@ -1,10 +1,16 @@
/* eslint-disable no-bitwise */
import * as events from 'events'; import * as events from 'events';
import * as tls from 'tls'; import * as tls from 'tls';
import { encodeTunnelPW, openTLSSockets, startTLSServer } from '../tls/crypt'; import { encodeTunnelPW, openTLSSockets, startTLSServer } from '../tls/crypt';
import { AdditionalAuthHandler, IResponseHandlers } from '../types/Handler'; import { AdditionalAuthHandler, ResponseAuthHandler } from '../types/Handler';
import { PAPChallenge } from './challenges/pap'; import { PAPChallenge } from './challenges/pap';
import { IEAPType } from '../types/EAPType'; import { IEAPType } from '../types/EAPType';
interface IEAPResponseHandlers {
response: (respData?: Buffer, msgType?: number) => void;
checkAuth: ResponseAuthHandler;
}
export class EAPTTLS implements IEAPType { export class EAPTTLS implements IEAPType {
papChallenge: PAPChallenge; papChallenge: PAPChallenge;
@ -12,23 +18,48 @@ export class EAPTTLS implements IEAPType {
this.papChallenge = new PAPChallenge(); this.papChallenge = new PAPChallenge();
} }
handleMessage(msg: Buffer, state: string, handlers, identifier: number) { decode(msg: Buffer) {
const flags = msg.slice(5, 6); // .toString('hex'); const flags = msg.slice(5, 6).readUInt8(0); // .toString('hex');
// if (flags) // if (flags)
// @todo check if "L" flag is set in flags // @todo check if "L" flag is set in flags
const msglength = msg.slice(6, 10).readInt32BE(0); // .toString('hex'); const decodedFlags = {
const data = msg.slice(6, msg.length); // 10); //.toString('hex'); lengthIncluded: flags & 0b010000000,
moreFragments: flags & 0b001000000,
start: flags & 0b000100000,
reserved: flags & 0b000011000,
version: flags & 0b010000111
};
let msglength;
if (decodedFlags.lengthIncluded) {
msglength = msg.slice(6, 10).readInt32BE(0); // .readDoubleLE(0); // .toString('hex');
}
const data = msg.slice(decodedFlags.lengthIncluded ? 10 : 6, msg.length);
return {
decodedFlags,
msglength,
data
};
}
handleMessage(msg: Buffer, state: string, handlers, identifier: number) {
const { decodedFlags, msglength, data } = this.decode(msg);
// check if no data package is there and we have something in the queue, if so.. empty the queue first // check if no data package is there and we have something in the queue, if so.. empty the queue first
if (!data) { if (!data || data.length === 0) {
// @todo: queue processing // @todo: queue processing
console.warn('no data, just a confirmation!'); console.warn(
`>>>>>>>>>>>> REQUEST FROM CLIENT: EAP TTLS, ACK / NACK (no data, just a confirmation, ID: ${identifier})`
);
return; return;
} }
console.log('incoming EAP TTLS', { console.log('>>>>>>>>>>>> REQUEST FROM CLIENT: EAP TTLS', {
flags /* // flags: `00000000${flags.toString(2)}`.substr(-8),
decodedFlags,
identifier,
/*
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+
| L | M | S | R | R | V | | L | M | S | R | R | V |
@ -39,14 +70,15 @@ export class EAPTTLS implements IEAPType {
S = Start S = Start
R = Reserved R = Reserved
V = Version (000 for EAP-TTLSv0) V = Version (000 for EAP-TTLSv0)
*/, */
msglength, msglength,
data, data,
dataStr: data.toString() dataStr: data.toString()
}); });
let currentConnection = openTLSSockets.get(state) as let currentConnection = openTLSSockets.get(state) as
| { events: events.EventEmitter; tls: tls.TLSSocket; currentHandlers: IResponseHandlers } | { events: events.EventEmitter; tls: tls.TLSSocket; currentHandlers: IEAPResponseHandlers }
| undefined; | undefined;
if (!currentConnection) { if (!currentConnection) {
const connection = startTLSServer(); const connection = startTLSServer();
@ -71,12 +103,15 @@ export class EAPTTLS implements IEAPType {
// pwd not found.. // pwd not found..
console.error('pwd not found', err); console.error('pwd not found', err);
// NAK // NAK
currentConnection!.currentHandlers.response(undefined, 3);
/*
this.sendEAPResponse( this.sendEAPResponse(
currentConnection!.currentHandlers.response, currentConnection!.currentHandlers.response,
identifier, identifier,
undefined, undefined,
3 3
); ); */
currentConnection!.events.emit('end'); currentConnection!.events.emit('end');
throw new Error(`pwd not found`); throw new Error(`pwd not found`);
} }
@ -85,16 +120,28 @@ export class EAPTTLS implements IEAPType {
console.log('data', incomingData); console.log('data', incomingData);
console.log('data str', incomingData.toString()); console.log('data str', incomingData.toString());
currentConnection!.events.emit('end'); // currentConnection!.events.emit('end');
throw new Error(`unsupported auth type${type}`);
console.log('UNSUPPORTED AUTH TYPE, requesting PAP');
// throw new Error(`unsupported auth type${type}`);
currentConnection!.currentHandlers.response(Buffer.from([1]), 3);
/*
this.sendEAPResponse(
currentConnection!.currentHandlers.response,
identifier,
Buffer.from([1]),
3
); */
} }
}); });
currentConnection.events.on('response', (responseData: Buffer) => { currentConnection.events.on('response', (responseData: Buffer) => {
console.log('sending encrypted data back to client', responseData); // console.log('sending encrypted data back to client', responseData);
// send back... // send back...
this.sendEAPResponse(currentConnection!.currentHandlers.response, identifier, responseData); currentConnection!.currentHandlers.response(responseData);
// this.sendEAPResponse(currentConnection!.currentHandlers.response, identifier, responseData);
// this.sendMessage(TYPE.PRELOGIN, data, false); // this.sendMessage(TYPE.PRELOGIN, data, false);
}); });
@ -103,13 +150,14 @@ export class EAPTTLS implements IEAPType {
console.log('ENDING SOCKET'); console.log('ENDING SOCKET');
openTLSSockets.del(state); openTLSSockets.del(state);
}); });
} else { } /* else {
console.log('using existing socket'); console.log('using existing socket');
} } */
// update handlers // update handlers
currentConnection.currentHandlers = { currentConnection.currentHandlers = {
...handlers, response: (respData?: Buffer, msgType?: number) =>
this.sendEAPResponse(handlers.response, identifier, respData, msgType),
checkAuth: (username: string, password: string) => { checkAuth: (username: string, password: string) => {
const additionalAuthHandler: AdditionalAuthHandler = (success, params) => { const additionalAuthHandler: AdditionalAuthHandler = (success, params) => {
const buffer = Buffer.from([ const buffer = Buffer.from([
@ -138,7 +186,7 @@ export class EAPTTLS implements IEAPType {
'ttls keying material' 'ttls keying material'
); );
console.log('keyingMaterial', keyingMaterial); // console.log('keyingMaterial', keyingMaterial);
// eapKeyData + len // eapKeyData + len
params.attributes.push([ params.attributes.push([

View File

@ -7,3 +7,33 @@ export function makeid(length) {
} }
return result; return result;
} }
export const MAX_RADIUS_ATTRIBUTE_SIZE = 253;
export interface IDeferredPromise {
promise: Promise<any>;
resolve: (value?: unknown) => Promise<void>;
reject: (reason?: any) => Promise<void>;
}
export const newDeferredPromise = (): IDeferredPromise => {
if (Promise && !('deferred' in Promise)) {
let fResolve;
let fReject;
const P = new Promise((resolve, reject) => {
fResolve = resolve;
fReject = reject;
});
return {
promise: P,
resolve: fResolve,
reject: fReject
};
}
return (Promise as any).deferred;
};
export const delay = (timeout: number) =>
new Promise(resolve => setTimeout(() => resolve(), timeout));

View File

@ -5,14 +5,21 @@ import { createSecureContext } from 'tls';
import * as fs from 'fs'; import * as fs from 'fs';
import * as crypto from 'crypto'; import * as crypto from 'crypto';
import * as DuplexPair from 'native-duplexpair'; import * as DuplexPair from 'native-duplexpair';
import * as constants from 'constants';
import { makeid } from '../helpers'; import { makeid } from '../helpers';
import * as config from '../../config';
// https://nodejs.org/api/tls.html // https://nodejs.org/api/tls.html
const tlsOptions = { const tlsOptions: tls.SecureContextOptions = {
cert: fs.readFileSync('./ssl/public-cert.pem'), ...config.certificate,
key: fs.readFileSync('./ssl/private-key.pem'), // ca: fs.readFileSync('./ssl/server.pem'),
ecdhCurve: 'auto' // eslint-disable-next-line no-bitwise
secureOptions: constants.SSL_OP_NO_TICKET // : constants.SSL_OP_NO_TLSv1_2 | constants.SSL_OP_NO_TLSv1_1,
// honorCipherOrder: true
// secureOptions:
// ecdhCurve: 'auto'
}; };
console.log('tlsOptions', 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
@ -22,7 +29,11 @@ export function startTLSServer(): { events: events.EventEmitter; tls: tls.TLSSoc
const cleartext = new tls.TLSSocket(duplexpair.socket1, { const cleartext = new tls.TLSSocket(duplexpair.socket1, {
secureContext, secureContext,
isServer: true isServer: true,
enableTrace: true,
rejectUnauthorized: false,
// handshakeTimeout: 10,
requestCert: false
}); });
const encrypted = duplexpair.socket2; const encrypted = duplexpair.socket2;
@ -71,6 +82,7 @@ export function startTLSServer(): { events: events.EventEmitter; tls: tls.TLSSoc
console.log('*********** new client connection established / secured ********'); console.log('*********** new client connection established / secured ********');
// this.emit('secure', securePair.cleartext); // this.emit('secure', securePair.cleartext);
// this.encryptAllFutureTraffic(); // this.encryptAllFutureTraffic();
console.log('GET FINSIHED', cleartext.getFinished());
}); });
cleartext.on('error', (err?: Error) => { cleartext.on('error', (err?: Error) => {

View File

@ -0,0 +1,3 @@
export interface IAuthentication {
authenticate(username: string, password: string): Promise<string>;
}

View File

@ -1,3 +1,3 @@
export interface IAuthChallenge { export interface IEAPChallenge {
decode(data: Buffer): { username: string; password: string }; decode(data: Buffer): { username: string; password: string };
} }

View File

@ -1,3 +1,3 @@
export interface IEAPType { export interface IEAPType {
handleMessage(msg: Buffer, state: string, handlers, identifier: number) handleMessage(msg: Buffer, state: string, handlers, identifier: number);
} }

View File

@ -1,6 +1,8 @@
import { RadiusPacket } from 'radius'; import { RadiusPacket } from 'radius';
export type ResponseHandler = (msg: Buffer) => void; export type ResponseHandler = (
msg: Buffer
) => Promise<{ identifier: number; response: ResponseHandler }>;
export type ResponseAuthHandler = ( export type ResponseAuthHandler = (
username: string, username: string,
password: string, password: string,

8
ssl/README.md Normal file
View File

@ -0,0 +1,8 @@
this is based on freeradius cert directory :)
1.) edit ca.cnf
2.) edit server.cnf
3.) replace your choosen pwd (deafult is whatever2020) in create.sh
4.) run ./create.sh
5.) set your choosen pwd in ~/config.js

61
ssl/ca.cnf Normal file
View File

@ -0,0 +1,61 @@
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = ./cert/
certs = $dir
crl_dir = $dir/crl
database = $dir/index.txt
new_certs_dir = $dir
certificate = $dir/ca.pem
serial = $dir/serial
crl = $dir/crl.pem
private_key = $dir/ca.key
RANDFILE = $dir/.rand
name_opt = ca_default
cert_opt = ca_default
default_days = 60
default_crl_days = 30
default_md = sha256
preserve = no
policy = policy_match
crlDistributionPoints = URI:http://www.example.org/example_ca.crl
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
prompt = no
distinguished_name = certificate_authority
default_bits = 2048
input_password = whatever2020
output_password = whatever2020
x509_extensions = v3_ca
[certificate_authority]
countryName = AT
stateOrProvinceName = Vienna
localityName = Vienna
organizationName = hokify.com
emailAddress = info@hokify.com
commonName = "hokify GmbH"
[v3_ca]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
basicConstraints = critical,CA:true
crlDistributionPoints = URI:http://www.example.org/example_ca.crl

0
ssl/cert/index.txt Normal file
View File

1
ssl/cert/serial Normal file
View File

@ -0,0 +1 @@
00

View File

@ -1,2 +1,15 @@
openssl genrsa -out private-key.pem 1024 # generate private key
openssl req -new -key private-key.pem -out csr.pem # openssl genrsa -out csr.key 2048
# CA
openssl req -new -x509 -keyout ca.key -out ca.pem -days 3600 -config ./ca.cnf
# server
openssl req -new -out server.csr -keyout server.key -config ./server.cnf
# sign it
# -key $(PASSWORD_CA) (default pwd is whatever2020)
openssl ca -batch -keyfile ca.key -cert ca.pem -in server.csr -key whatever2020 -out server.crt -extensions xpserver_ext -extfile xpextensions -config ./server.cnf
# sign it
# openssl x509 -req -in csr.pem -signkey private-key.pem -out public-cert.pem

54
ssl/server.cnf Normal file
View File

@ -0,0 +1,54 @@
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = ./cert/
certs = $dir
crl_dir = $dir/crl
database = $dir/index.txt
new_certs_dir = $dir
certificate = $dir/server.pem
serial = $dir/serial
crl = $dir/crl.pem
private_key = $dir/server.key
RANDFILE = $dir/.rand
name_opt = ca_default
cert_opt = ca_default
default_days = 6000
default_crl_days = 30
default_md = sha256
preserve = no
policy = policy_match
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
prompt = no
distinguished_name = server
default_bits = 2048
input_password = whatever2020
output_password = whatever2020
[server]
countryName = AT
stateOrProvinceName = Vienna
localityName = Vienna
organizationName = hokify.com
emailAddress = info@hokify.com
commonName = "hokify GmbH"

View File

@ -1 +0,0 @@
openssl x509 -req -in csr.pem -signkey private-key.pem -out public-cert.pem

24
ssl/xpextensions Normal file
View File

@ -0,0 +1,24 @@
#
# File containing the OIDs required for Windows.
#
# http://support.microsoft.com/kb/814394/en-us
#
[ xpclient_ext]
extendedKeyUsage = 1.3.6.1.5.5.7.3.2
crlDistributionPoints = URI:http://www.example.com/example_ca.crl
[ xpserver_ext]
extendedKeyUsage = 1.3.6.1.5.5.7.3.1
crlDistributionPoints = URI:http://www.example.com/example_ca.crl
#
# Add this to the PKCS#7 keybag attributes holding the client's private key
# for machine authentication.
#
# the presence of this OID tells Windows XP that the cert is intended
# for use by the computer itself, and not by an end-user.
#
# The other solution is to use Microsoft's web certificate server
# to generate these certs.
#
# 1.3.6.1.4.1.311.17.2