refactor: improve ttls tunnel stuff and fix some byte sizes for AVPs

This commit is contained in:
simon 2020-02-25 11:54:57 +01:00
parent 6aa4b9f92e
commit 60ec84ae8e
13 changed files with 296 additions and 159 deletions

View File

@ -5,12 +5,16 @@ Basic RADIUS Server for node.js for Google LDAP Service and WPA2 Enteprise WLAN
Protect your WIFI access with a username and password by a credential provider you already use!
Authenticiation tested with Windows, Linux, Android and Apple devices.
## Known Issues / Disclaimer
This is a first implementation draft, which is currently only working with a nodejs fork (see https://github.com/nodejs/node/pull/31814).
This is a first implementation, which is currently only working with node js nightly (node 13+) (see https://github.com/nodejs/node/pull/31814).
- PAP / CHAP RFC not found to implement this correctly
- a lot of bugs
- MD5 Challenge not implenented, but RFC says this is mandatory ;-)
- Inner Tunnel does not act differently, even though spec says that EAP-message are not allowed to get fragmented,
this is not a problem right now, as the messages of the inner tunnel are small enough, but it could be a bug in the future.
ways to approach this: refactor that the inner tunnel can set max fragment size, or rebuild eap fragments in ttls after inner tunnel response
CONTRIBUTIONS WELCOME! If you are willing to help, just open a PR or contact me via bug system or simon.tretter@hokify.com.

View File

@ -39,7 +39,6 @@ export class LDAPAuth implements IAuthentication {
}
async authenticate(username: string, password: string) {
// console.log('AUTH', this.ldap);
const authResult: boolean = await new Promise((resolve, reject) => {
this.ldap.authenticate(username, password, function(err, user) {
if (err) {

View File

@ -0,0 +1,40 @@
import { IPacket, IPacketHandler, IPacketHandlerResult } from '../types/PacketHandler';
import { IAuthentication } from '../types/Authentication';
import { EAPPacketHandler } from './handler/EAPPacketHandler';
import { EAPTTLS } from './handler/eap/eapMethods/EAP-TTLS';
import { EAPGTC } from './handler/eap/eapMethods/EAP-GTC';
import { EAPMD5 } from './handler/eap/eapMethods/EAP-MD5';
import { UserPasswordPacketHandler } from './handler/UserPasswordPacketHandler';
export class PacketHandler implements IPacketHandler {
packetHandlers: IPacketHandler[] = [];
constructor(authentication: IAuthentication) {
this.packetHandlers.push(
new EAPPacketHandler([
new EAPTTLS(authentication, this),
new EAPGTC(authentication),
new EAPMD5(authentication)
])
);
this.packetHandlers.push(new UserPasswordPacketHandler(authentication));
}
async handlePacket(packet: IPacket, handlingType?: number) {
let response: IPacketHandlerResult;
let i = 0;
if (!this.packetHandlers[i]) {
throw new Error('no packet handlers registered');
}
// process packet handlers until we get a response from one
do {
/* response is of type IPacketHandlerResult */
response = await this.packetHandlers[i].handlePacket(packet, handlingType);
i++;
} while (this.packetHandlers[i] && (!response || !response.code));
return response;
}
}

View File

@ -1,25 +1,14 @@
import * as radius from 'radius';
import { IAuthentication } from '../types/Authentication';
import { EAPPacketHandler } from './handler/EAPPacketHandler';
import { DefaultPacketHandler } from './handler/DefaultPacketHandler';
import { IPacketHandler, IPacketHandlerResult, PacketResponseCode } from '../types/PacketHandler';
import { IPacketHandlerResult, PacketResponseCode } from '../types/PacketHandler';
import { EAPTTLS } from './handler/eap/eapMethods/EAP-TTLS';
import { EAPMD5 } from './handler/eap/eapMethods/EAP-MD5';
import { EAPGTC } from './handler/eap/eapMethods/EAP-GTC';
import { PacketHandler } from './PacketHandler';
export class RadiusService {
radiusPacketHandlers: IPacketHandler[] = [];
private packetHandler: PacketHandler;
constructor(private secret: string, private authentication: IAuthentication) {
this.radiusPacketHandlers.push(
new EAPPacketHandler([
new EAPTTLS(authentication),
new EAPGTC(authentication),
new EAPMD5(authentication)
])
);
this.radiusPacketHandlers.push(new DefaultPacketHandler(authentication));
constructor(private secret: string, authentication: IAuthentication) {
this.packetHandler = new PacketHandler(authentication);
}
async handleMessage(
@ -32,19 +21,7 @@ export class RadiusService {
return undefined;
}
let response: IPacketHandlerResult;
let i = 0;
if (!this.radiusPacketHandlers[i]) {
throw new Error('no packet handlers registered');
}
// process packet handlers until we get a response from one
do {
/* response is of type IPacketHandlerResult */
response = await this.radiusPacketHandlers[i].handlePacket(packet.attributes, packet);
i++;
} while (this.radiusPacketHandlers[i] && (!response || !response.code));
const response: IPacketHandlerResult = await this.packetHandler.handlePacket(packet);
// still no response, we are done here
if (!response || !response.code) {

View File

@ -1,40 +1,38 @@
// https://tools.ietf.org/html/rfc3748#section-4.1
import * as NodeCache from 'node-cache';
import { RadiusPacket } from 'radius';
import debug from 'debug';
import { makeid } from '../../helpers';
import { IPacketHandler, IPacketHandlerResult } from '../../types/PacketHandler';
import { IPacket, IPacketHandler, IPacketHandlerResult } from '../../types/PacketHandler';
import { IEAPMethod } from '../../types/EAPMethod';
import { buildEAPResponse, decodeEAPHeader } from './eap/EAPHelper';
const log = debug('radius:eap');
export class EAPPacketHandler implements IPacketHandler {
private identities = new NodeCache({ useClones: false, stdTTL: 60 }); // queue data maximum for 60 seconds
// private eapConnectionStates: { [key: string]: { validMethods: IEAPMethod[] } } = {};
private eapConnectionStates = new NodeCache({ useClones: false, stdTTL: 3600 }); // max for one hour
constructor(private eapMethods: IEAPMethod[]) {}
async handlePacket(
attributes: { [key: string]: Buffer | string },
orgRadiusPacket: RadiusPacket
): Promise<IPacketHandlerResult> {
if (!attributes['EAP-Message']) {
async handlePacket(packet: IPacket, handlingType?: number): Promise<IPacketHandlerResult> {
if (!packet.attributes['EAP-Message']) {
// not an EAP message
return {};
}
const stateID = (attributes.State && attributes.State.toString()) || makeid(16);
const stateID = (packet.attributes.State && packet.attributes.State.toString()) || makeid(16);
if (!this.eapConnectionStates.get(stateID)) {
this.eapConnectionStates.set(stateID, {
validMethods: this.eapMethods // on init all registered eap methods are valid, we kick them out in case we get a NAK response
validMethods: this.eapMethods.filter(eap => eap.getEAPType() !== handlingType) // on init all registered eap methods are valid, we kick them out in case we get a NAK response
});
}
// EAP MESSAGE
const msg = attributes['EAP-Message'] as Buffer;
const msg = packet.attributes['EAP-Message'] as Buffer;
const { code, type, identifier, data } = decodeEAPHeader(msg);
@ -45,7 +43,13 @@ export class EAPPacketHandler implements IPacketHandler {
case 2: // for response
switch (type) {
case 1: // identifiy
log('>>>>>>>>>>>> REQUEST FROM CLIENT: IDENTIFY', {});
log('>>>>>>>>>>>> REQUEST FROM CLIENT: IDENTIFY', stateID, data.toString());
if (data) {
this.identities.set(stateID, data); // use token til binary 0.);
} else {
log('no msg');
}
// start identify
if (currentState.validMethods.length > 0) {
return currentState.validMethods[0].identify(identifier, stateID, data);
@ -65,6 +69,7 @@ export class EAPPacketHandler implements IPacketHandler {
console.error('not implemented type', type);
break;
case 3: // nak
// console.log('got NAK', data);
if (data) {
// if there is data, each data octect reprsents a eap method the clients supports,
// kick out all unsupported ones
@ -73,27 +78,38 @@ export class EAPPacketHandler implements IPacketHandler {
supportedEAPMethods.push(supportedMethod);
}
this.eapConnectionStates.set(stateID, {
...currentState,
validMethods: currentState.validMethods.filter(method => {
return supportedEAPMethods.includes(method.getEAPType()); // kick it out?
})
currentState.validMethods = currentState.validMethods.filter(method => {
return supportedEAPMethods.includes(method.getEAPType()); // kick it out?
});
// save
this.eapConnectionStates.set(stateID, currentState);
// new identidy request
// start identify
if (currentState.validMethods.length > 0) {
return currentState.validMethods[0].identify(identifier, stateID, data);
}
}
// continue with responding a NAK and add rest of supported methods
// eslint-disable-next-line no-fallthrough
default: {
const eapMethod = currentState.validMethods.find(method => {
const eapMethod = this.eapMethods.find(method => {
return type === method.getEAPType();
});
if (eapMethod) {
return eapMethod.handleMessage(identifier, stateID, msg, orgRadiusPacket);
return eapMethod.handleMessage(
identifier,
stateID,
msg,
packet,
this.identities.get(stateID)
);
}
// we do not support this auth type, ask for something we support
const serverSupportedMethods = currentState.validMethods.map(
method => method.getEAPType
const serverSupportedMethods = currentState.validMethods.map(method =>
method.getEAPType()
);
console.error('unsupported type', type, `requesting: ${serverSupportedMethods}`);

View File

@ -1,22 +1,29 @@
import debug from 'debug';
import { IAuthentication } from '../../types/Authentication';
import {
IPacket,
IPacketHandler,
IPacketHandlerResult,
PacketResponseCode
} from '../../types/PacketHandler';
export class DefaultPacketHandler implements IPacketHandler {
const log = debug('radius:user-pwd');
export class UserPasswordPacketHandler implements IPacketHandler {
constructor(private authentication: IAuthentication) {}
async handlePacket(attributes: { [key: string]: Buffer }): Promise<IPacketHandlerResult> {
const username = attributes['User-Name'];
const password = attributes['User-Password'];
async handlePacket(packet: IPacket): Promise<IPacketHandlerResult> {
const username = packet.attributes['User-Name'];
const password = packet.attributes['User-Password'];
if (!username || !password) {
// params missing, this handler cannot continue...
return {};
}
log('username', username, username.toString());
log('token', password, password.toString());
const authenticated = await this.authentication.authenticate(
username.toString(),
password.toString()
@ -24,7 +31,8 @@ export class DefaultPacketHandler implements IPacketHandler {
if (authenticated) {
// success
return {
code: PacketResponseCode.AccessAccept
code: PacketResponseCode.AccessAccept,
attributes: [['User-Name', username]]
};
}

View File

@ -1,7 +1,6 @@
// https://tools.ietf.org/html/rfc5281 TTLS v0
// https://tools.ietf.org/html/draft-funk-eap-ttls-v1-00 TTLS v1 (not implemented)
/* eslint-disable no-bitwise */
import * as NodeCache from 'node-cache';
import debug from 'debug';
import { IPacketHandlerResult, PacketResponseCode } from '../../../../types/PacketHandler';
import { IEAPMethod } from '../../../../types/EAPMethod';
@ -11,24 +10,19 @@ import { buildEAPResponse, decodeEAPHeader } from '../EAPHelper';
const log = debug('radius:eap:gtc');
export class EAPGTC implements IEAPMethod {
private loginData = new NodeCache({ useClones: false, stdTTL: 60 }); // queue data maximum for 60 seconds
getEAPType(): number {
return 6;
}
identify(identifier: number, stateID: string, msg?: Buffer): IPacketHandlerResult {
if (msg) {
const parsedMsg = msg.slice(
0,
msg.findIndex(v => v === 0)
);
log('identify', parsedMsg, parsedMsg.toString());
this.loginData.set(stateID, parsedMsg); // use token til binary 0.);
} else {
log('no msg');
extractValue(msg: Buffer) {
let tillBinary0 = msg.findIndex(v => v === 0) || msg.length;
if (tillBinary0 < 0) {
tillBinary0 = msg.length - 1;
}
return msg.slice(0, tillBinary0 + 1); // use token til binary 0.
}
identify(identifier: number, _stateID: string): IPacketHandlerResult {
return buildEAPResponse(identifier, 6, Buffer.from('Password: '));
}
@ -36,18 +30,16 @@ export class EAPGTC implements IEAPMethod {
async handleMessage(
_identifier: number,
stateID: string,
msg: Buffer
_stateID: string,
msg: Buffer,
_,
identity?: string
): Promise<IPacketHandlerResult> {
const username = this.loginData.get(stateID) as Buffer | undefined;
const username = identity; // this.loginData.get(stateID) as Buffer | undefined;
const { data } = decodeEAPHeader(msg);
let tillBinary0 = data.findIndex(v => v === 0) || data.length;
if (tillBinary0 < 0) {
tillBinary0 = data.length - 1;
}
const token = data.slice(0, tillBinary0 + 1); // use token til binary 0.
const token = this.extractValue(data);
if (!username) {
throw new Error('no username');
@ -59,7 +51,8 @@ export class EAPGTC implements IEAPMethod {
const success = await this.authentication.authenticate(username.toString(), token.toString());
return {
code: success ? PacketResponseCode.AccessAccept : PacketResponseCode.AccessReject
code: success ? PacketResponseCode.AccessAccept : PacketResponseCode.AccessReject,
attributes: (success && [['User-Name', username]]) || undefined
};
}
}

View File

@ -8,8 +8,6 @@ import { IPacketHandlerResult } from '../../../../types/PacketHandler';
import { IEAPMethod } from '../../../../types/EAPMethod';
import { IAuthentication } from '../../../../types/Authentication';
const log = debug('radius:eap:md5');
interface IEAPResponseHandlers {
response: (respData?: Buffer, msgType?: number) => void;
checkAuth: ResponseAuthHandler;

View File

@ -3,18 +3,23 @@
/* eslint-disable no-bitwise */
import * as tls from 'tls';
import * as NodeCache from 'node-cache';
import { RadiusPacket } from 'radius';
// @ts-ignore
import { attr_id_to_name, attr_name_to_id } from 'radius';
import debug from 'debug';
import { encodeTunnelPW, ITLSServer, startTLSServer } from '../../../../tls/crypt';
import { ResponseAuthHandler } from '../../../../types/Handler';
import { PAPChallenge } from './challenges/PAPChallenge';
import { IPacketHandlerResult, PacketResponseCode } from '../../../../types/PacketHandler';
import {
IPacket,
IPacketAttributes,
IPacketHandler,
IPacketHandlerResult,
PacketResponseCode
} from '../../../../types/PacketHandler';
import { MAX_RADIUS_ATTRIBUTE_SIZE, newDeferredPromise } from '../../../../helpers';
import { IEAPMethod } from '../../../../types/EAPMethod';
import { IAuthentication } from '../../../../types/Authentication';
import { secret } from '../../../../../config';
import { EAPPacketHandler } from '../../EAPPacketHandler';
import { EAPGTC } from './EAP-GTC';
const log = debug('radius:eap:ttls');
@ -31,17 +36,24 @@ function tlsHasExportKeyingMaterial(
return typeof (tlsSocket as any).exportKeyingMaterial === 'function';
}
export class EAPTTLS implements IEAPMethod {
private papChallenge: PAPChallenge = new PAPChallenge();
interface IAVPEntry {
type: number;
flags: string;
decodedFlags: {
V: boolean;
M: boolean;
};
length: number;
vendorId?: number;
data: Buffer;
}
export class EAPTTLS implements IEAPMethod {
// { [key: string]: Buffer } = {};
private queueData = new NodeCache({ useClones: false, stdTTL: 60 }); // queue data maximum for 60 seconds
private openTLSSockets = new NodeCache({ useClones: false, stdTTL: 3600 }); // keep sockets for about one hour
// EAP TUNNEL
tunnelEAP = new EAPPacketHandler([new EAPGTC(this.authentication)]); // tunnel with GTC support
getEAPType(): number {
return 21;
}
@ -50,7 +62,7 @@ export class EAPTTLS implements IEAPMethod {
return this.buildEAPTTLSResponse(identifier, 21, 0x20, stateID);
}
constructor(private authentication: IAuthentication) {}
constructor(private authentication: IAuthentication, private innerTunnel: IPacketHandler) {}
private buildEAPTTLS(
identifier: number,
@ -179,7 +191,7 @@ export class EAPTTLS implements IEAPMethod {
Message Length | Data...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
const identifier = msg.slice(1, 2).readUInt8(0);
// const identifier = msg.slice(1, 2).readUInt8(0);
const flags = msg.slice(5, 6).readUInt8(0); // .toString('hex');
/*
0 1 2 3 4 5 6 7
@ -215,7 +227,7 @@ export class EAPTTLS implements IEAPMethod {
log('>>>>>>>>>>>> REQUEST FROM CLIENT: EAP TTLS', {
flags: `00000000${flags.toString(2)}`.substr(-8),
decodedFlags,
identifier,
// identifier,
msglength,
data
// dataStr: data.toString()
@ -232,7 +244,7 @@ export class EAPTTLS implements IEAPMethod {
identifier: number,
success: boolean,
socket: tls.TLSSocket,
packet: RadiusPacket
packet: IPacket
): IPacketHandlerResult {
const buffer = Buffer.from([
success ? 3 : 4, // 3.. success, 4... failure
@ -246,22 +258,26 @@ export class EAPTTLS implements IEAPMethod {
if (packet.attributes && packet.attributes['User-Name']) {
// reappend username to response
attributes.push(['User-Name', packet.attributes['User-Name']]);
attributes.push(['User-Name', packet.attributes['User-Name'].toString()]);
}
if (tlsHasExportKeyingMaterial(socket)) {
const keyingMaterial = (socket as any).exportKeyingMaterial(128, 'ttls keying material');
const keyingMaterial = socket.exportKeyingMaterial(128, 'ttls keying material');
if (!packet.authenticator) {
throw new Error('FATAL: no packet authenticator variable set');
}
attributes.push([
'Vendor-Specific',
311,
[[16, encodeTunnelPW(keyingMaterial.slice(64), (packet as any).authenticator, secret)]]
[[16, encodeTunnelPW(keyingMaterial.slice(64), packet.authenticator, secret)]]
]); // MS-MPPE-Send-Key
attributes.push([
'Vendor-Specific',
311,
[[17, encodeTunnelPW(keyingMaterial.slice(0, 64), (packet as any).authenticator, secret)]]
[[17, encodeTunnelPW(keyingMaterial.slice(0, 64), packet.authenticator, secret)]]
]); // MS-MPPE-Recv-Key
} else {
console.error(
@ -279,7 +295,7 @@ export class EAPTTLS implements IEAPMethod {
identifier: number,
stateID: string,
msg: Buffer,
orgRadiusPacket: RadiusPacket
packet: IPacket
): Promise<IPacketHandlerResult> {
const { data } = this.decodeTTLSMessage(msg);
@ -313,12 +329,58 @@ export class EAPTTLS implements IEAPMethod {
ret.attributes = {};
ret.raw_attributes = [];
const { type, data: AVPdata, length: AVPlength } = this.decodeAVP(incomingData);
const AVPs = this.decodeAVPs(incomingData);
console.log('AVP data', { AVPdata, AVPlength, AVPdataStr: AVPdata.toString() });
// build attributes for packet handler
const attributes: IPacketAttributes = {};
AVPs.forEach(avp => {
attributes[attr_id_to_name(avp.type)] = avp.data;
});
// const code = data.slice(4, 5).readUInt8(0);
attributes.State = `${stateID}-inner`;
// handle incoming package via inner tunnel
const result = await this.innerTunnel.handlePacket(
{
attributes
},
this.getEAPType()
);
log('inner tunnel result', result);
if (
result.code === PacketResponseCode.AccessReject ||
result.code === PacketResponseCode.AccessAccept
) {
sendResponsePromise.resolve(
this.authResponse(
identifier,
result.code === PacketResponseCode.AccessAccept,
connection.tls,
{
...packet,
attributes: {
...packet.attributes,
...this.transformAttributesArrayToMap(result.attributes)
}
}
)
);
return;
}
const eapMessage = result.attributes?.find(attr => attr[0] === 'EAP-Message');
if (!eapMessage) {
throw new Error('no eap message found');
}
connection.events.emit(
'encrypt',
this.buildAVP(attr_name_to_id('EAP-Message'), eapMessage[1] as Buffer)
);
/*
switch (type) {
case 1: // PAP
try {
@ -381,7 +443,7 @@ export class EAPTTLS implements IEAPMethod {
this.buildAVP(79, this.buildEAPTTLS(identifier, 3, 0, stateID, Buffer.from([1])))
);
}
}
} */
};
const responseHandler = (encryptedResponseData: Buffer) => {
@ -407,9 +469,31 @@ export class EAPTTLS implements IEAPMethod {
return responseData; // this.buildEAPTTLSResponse(identifier, 21, 0x00, stateID, encryptedResponseData);
}
private decodeAVP(buffer: Buffer) {
/**
* 4.1. AVP Header
private transformAttributesArrayToMap(attributes: [string, Buffer | string][] | undefined) {
const result = {};
attributes?.forEach(([key, value]) => {
result[key] = value;
});
return result;
}
private decodeAVPs(buffer: Buffer): IAVPEntry[] {
const results: {
type: number;
flags: string;
decodedFlags: {
V: boolean;
M: boolean;
};
length: number;
vendorId?: number;
data: Buffer;
}[] = [];
let currentBuffer = buffer;
do {
/**
* 4.1. AVP Header
The fields in the AVP header MUST be sent in network byte order. The
format of the header is:
@ -425,37 +509,47 @@ export class EAPTTLS implements IEAPMethod {
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data ...
+-+-+-+-+-+-+-+-+
*/
const type = buffer.slice(0, 4).readUInt32BE(0);
const flags = buffer.slice(4, 5).readUInt8(0);
const decodedFlags = {
// L
V: !!(flags & 0b10000000),
// M
M: !!(flags & 0b01000000)
};
*/
const type = currentBuffer.slice(0, 4).readUInt32BE(0);
const flags = currentBuffer.slice(4, 5).readUInt8(0);
const decodedFlags = {
// L
V: !!(flags & 0b10000000),
// M
M: !!(flags & 0b01000000)
};
// const length = buffer.slice(5, 8).readUInt16BE(0); // actually a Int24BE
const length = buffer.slice(6, 8).readUInt16BE(0); // actually a Int24BE
// const length = buffer.slice(5, 8).readUInt16BE(0); // actually a Int24BE
const length = currentBuffer.slice(6, 8).readUInt16BE(0); // actually a Int24BE
let vendorId;
let data;
if (flags & 0b010000000) {
// V flag set
vendorId = buffer.slice(8, 12).readUInt32BE(0);
data = buffer.slice(8, 12);
} else {
data = buffer.slice(8);
}
let vendorId;
let data;
if (flags & 0b010000000) {
// V flag set
vendorId = currentBuffer.slice(8, 12).readUInt32BE(0);
data = currentBuffer.slice(12, length);
} else {
data = currentBuffer.slice(8, length);
}
return {
type,
flags: `00000000${flags.toString(2)}`.substr(-8),
decodedFlags,
length,
vendorId,
data
};
results.push({
type,
flags: `00000000${flags.toString(2)}`.substr(-8),
decodedFlags,
length,
vendorId,
data
});
// ensure length is a multiple of 4 octect
let totalAVPSize = length;
while (totalAVPSize % 4 !== 0) {
totalAVPSize += 1;
}
currentBuffer = currentBuffer.slice(totalAVPSize);
} while (currentBuffer.length > 0);
return results;
}
private buildAVP(
@ -481,9 +575,9 @@ export class EAPTTLS implements IEAPMethod {
| Data ...
+-+-+-+-+-+-+-+-+
*/
let b = Buffer.alloc(8);
let AVP = Buffer.alloc(8);
b.writeInt32BE(code, 0); // EAP-Message
AVP.writeInt32BE(code, 0); // EAP-Message
/**
* The 'V' (Vendor-Specific) bit indicates whether the optional
Vendor-ID field is present. When set to 1, the Vendor-ID field is
@ -506,14 +600,19 @@ export class EAPTTLS implements IEAPMethod {
flagValue += 0b01000000;
}
console.log('flagValue', flagValue, `00000000${flagValue.toString(2)}`.substr(-8));
// log('flagValue', flagValue, `00000000${flagValue.toString(2)}`.substr(-8));
b.writeInt8(flagValue, 4); // flags (set V..)
AVP.writeInt8(flagValue, 4); // flags (set V..)
b = Buffer.concat([b, data]); // , Buffer.from('\0')]);
AVP = Buffer.concat([AVP, data]); // , Buffer.from('\0')]);
b.writeInt16BE(b.byteLength, 6); // write size (actually we would need a Int24BE here, but it is good to go with 16bits)
AVP.writeInt16BE(AVP.byteLength, 6); // write size (actually we would need a Int24BE here, but it is good to go with 16bits)
return b;
// fill up with 0x00 till we have % 4
while (AVP.length % 4 !== 0) {
AVP = Buffer.concat([AVP, Buffer.from([0x00])]);
}
return AVP;
}
}

View File

@ -5,7 +5,6 @@ import * as crypto from 'crypto';
import * as DuplexPair from 'native-duplexpair';
import * as constants from 'constants';
import debug from 'debug';
import { makeid } from '../helpers';
import * as config from '../../config';
const log = debug('radius:tls');
@ -136,11 +135,10 @@ export function encodeTunnelPW(key: Buffer, authenticator: Buffer, secret: strin
contents of each Salt field in a given Access-Accept packet MUST
be unique.
*/
const salt = Buffer.concat([
// eslint-disable-next-line no-bitwise
Buffer.from((Number(makeid(1)) & 0b10000000).toString()), // ensure left most bit is set (1)
Buffer.from(makeid(1))
]);
const salt = crypto.randomBytes(2);
// eslint-disable-next-line no-bitwise
salt[0] |= 0b10000000; // ensure leftmost bit is set to 1
/*
String

View File

@ -1,5 +1,4 @@
import { RadiusPacket } from 'radius';
import { IPacketHandlerResult } from './PacketHandler';
import { IPacket, IPacketHandlerResult } from './PacketHandler';
export interface IEAPMethod {
getEAPType(): number;
@ -10,6 +9,7 @@ export interface IEAPMethod {
identifier: number,
stateID: string,
msg: Buffer,
orgRadiusPacket?: RadiusPacket
packet?: IPacket,
identity?: string
): Promise<IPacketHandlerResult>;
}

View File

@ -1,5 +1,3 @@
import { RadiusPacket } from 'radius';
export enum PacketResponseCode {
AccessChallenge = 'Access-Challenge',
AccessAccept = 'Access-Accept',
@ -8,12 +6,19 @@ export enum PacketResponseCode {
export interface IPacketHandlerResult {
code?: PacketResponseCode;
attributes?: [string, Buffer][];
attributes?: [string, Buffer | string][];
}
export interface IPacketAttributes {
[key: string]: string | Buffer;
}
export interface IPacket {
attributes: { [key: string]: string | Buffer };
authenticator?: Buffer;
}
export interface IPacketHandler {
handlePacket(
attributes: { [key: string]: Buffer },
orgRadiusPacket: RadiusPacket
): Promise<IPacketHandlerResult>;
/** handlingType is the attreibute ID of the currently processing type (e.g. TTLS, GTC, MD5,..) */
handlePacket(packet: IPacket, handlingType?: number): Promise<IPacketHandlerResult>;
}