feat: inner tunnel for TTSL support added

master
simon 4 years ago
parent 191bb54264
commit 6aa4b9f92e

@ -18,6 +18,7 @@ export class Authentication implements IAuthentication {
}
const authResult = await this.authenticator.authenticate(username, password);
console.log(`Auth Result for user ${username}`, authResult ? 'SUCCESS' : 'Failure');
this.cache.set(cacheKey, authResult, 86400); // cache for one day
return authResult;

@ -113,7 +113,7 @@ export class GoogleLDAPAuth implements IAuthentication {
if (!dnsFetched && !forceFetching) {
return this.authenticate(username, password, count, true);
}
console.error(`invalid username, not found in DN: ${username}`, this.allValidDNsCache);
console.error(`invalid username, not found in DN: ${username}`); // , this.allValidDNsCache);
return false;
}

@ -4,11 +4,21 @@ import { EAPPacketHandler } from './handler/EAPPacketHandler';
import { DefaultPacketHandler } from './handler/DefaultPacketHandler';
import { IPacketHandler, 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';
export class RadiusService {
radiusPacketHandlers: IPacketHandler[] = [];
constructor(private secret: string, private authentication: IAuthentication) {
this.radiusPacketHandlers.push(new EAPPacketHandler(authentication));
this.radiusPacketHandlers.push(
new EAPPacketHandler([
new EAPTTLS(authentication),
new EAPGTC(authentication),
new EAPMD5(authentication)
])
);
this.radiusPacketHandlers.push(new DefaultPacketHandler(authentication));
}

@ -3,103 +3,21 @@
import * as NodeCache from 'node-cache';
import { RadiusPacket } from 'radius';
import debug from 'debug';
import { EAPTTLS } from './eapMethods/EAPTTLS';
import { makeid } from '../../helpers';
import {
IPacketHandler,
IPacketHandlerResult,
PacketResponseCode
} from '../../types/PacketHandler';
import { IAuthentication } from '../../types/Authentication';
import { 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 eapMethods: IEAPMethod[] = [];
// private eapConnectionStates: { [key: string]: { validMethods: IEAPMethod[] } } = {};
private eapConnectionStates = new NodeCache({ useClones: false, stdTTL: 3600 }); // max for one hour
constructor(authentication: IAuthentication) {
this.eapMethods.push(new EAPTTLS(authentication));
}
/**
*
* @param data
* @param msgType 1 = identity, 21 = EAP-TTLS, 2 = notification, 4 = md5-challenge, 3 = NAK
*/
private async buildEAPResponse(
identifier: number,
msgType: number,
data?: Buffer
): Promise<IPacketHandlerResult> {
/** build a package according to this:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Code | Identifier | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Type-Data ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
*/
const buffer = Buffer.from([
1, // request
identifier,
0, // length (1/2)
0, // length (2/2)
msgType // 1 = identity, 21 = EAP-TTLS, 2 = notificaiton, 4 = md5-challenge, 3 = NAK
]);
const resBuffer = data ? Buffer.concat([buffer, data]) : buffer;
// set EAP length header
resBuffer.writeUInt16BE(resBuffer.byteLength, 2);
return {
code: PacketResponseCode.AccessChallenge,
attributes: [['EAP-Message', buffer]]
};
}
private decodeEAPHeader(msg: Buffer) {
/**
* parse msg according to this:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Code | Identifier | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Type-Data ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
*/
/*
code:
1 Request
2 Response
3 Success
4 Failure
*/
const code = msg.slice(0, 1).readUInt8(0);
/* identifier is a number */
const identifier = msg.slice(1, 2).readUInt8(0);
const length = msg.slice(2, 4).readInt16BE(0);
/* EAP type */
const type = msg.slice(4, 5).readUInt8(0);
const data = msg.slice(5);
return {
code,
identifier,
length,
type,
data
};
}
constructor(private eapMethods: IEAPMethod[]) {}
async handlePacket(
attributes: { [key: string]: Buffer },
attributes: { [key: string]: Buffer | string },
orgRadiusPacket: RadiusPacket
): Promise<IPacketHandlerResult> {
if (!attributes['EAP-Message']) {
@ -116,9 +34,9 @@ export class EAPPacketHandler implements IPacketHandler {
}
// EAP MESSAGE
const msg = attributes['EAP-Message'];
const msg = attributes['EAP-Message'] as Buffer;
const { code, type, identifier, data } = this.decodeEAPHeader(msg);
const { code, type, identifier, data } = decodeEAPHeader(msg);
const currentState = this.eapConnectionStates.get(stateID) as { validMethods: IEAPMethod[] };
@ -130,10 +48,10 @@ export class EAPPacketHandler implements IPacketHandler {
log('>>>>>>>>>>>> REQUEST FROM CLIENT: IDENTIFY', {});
// start identify
if (currentState.validMethods.length > 0) {
return currentState.validMethods[0].identify(identifier, stateID);
return currentState.validMethods[0].identify(identifier, stateID, data);
}
return this.buildEAPResponse(identifier, 3);
return buildEAPResponse(identifier, 3); // NAK
case 2: // notification
log('>>>>>>>>>>>> REQUEST FROM CLIENT: notification', {});
console.info('notification');
@ -180,7 +98,7 @@ export class EAPPacketHandler implements IPacketHandler {
console.error('unsupported type', type, `requesting: ${serverSupportedMethods}`);
return this.buildEAPResponse(identifier, 3, Buffer.from(serverSupportedMethods));
return buildEAPResponse(identifier, 3, Buffer.from(serverSupportedMethods));
}
}
break;

@ -0,0 +1,79 @@
import { IPacketHandlerResult, PacketResponseCode } from '../../../types/PacketHandler';
export function buildEAP(identifier: number, msgType: number, data?: Buffer) {
/** build a package according to this:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Code | Identifier | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Type-Data ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
*/
const buffer = Buffer.from([
1, // request
identifier,
0, // length (1/2)
0, // length (2/2)
msgType // 1 = identity, 21 = EAP-TTLS, 2 = notificaiton, 4 = md5-challenge, 3 = NAK
]);
const resBuffer = data ? Buffer.concat([buffer, data]) : buffer;
// set EAP length header
resBuffer.writeUInt16BE(resBuffer.byteLength, 2);
return resBuffer;
}
/**
*
* @param data
* @param msgType 1 = identity, 21 = EAP-TTLS, 2 = notification, 4 = md5-challenge, 3 = NAK
*/
export function buildEAPResponse(
identifier: number,
msgType: number,
data?: Buffer
): IPacketHandlerResult {
return {
code: PacketResponseCode.AccessChallenge,
attributes: [['EAP-Message', buildEAP(identifier, msgType, data)]]
};
}
export function decodeEAPHeader(msg: Buffer) {
/**
* parse msg according to this:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Code | Identifier | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Type-Data ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
*/
/*
code:
1 Request
2 Response
3 Success
4 Failure
*/
const code = msg.slice(0, 1).readUInt8(0);
/* identifier is a number */
const identifier = msg.slice(1, 2).readUInt8(0);
const length = msg.slice(2, 4).readUInt16BE(0);
/* EAP type */
const type = msg.slice(4, 5).readUInt8(0);
const data = msg.slice(5);
return {
code,
identifier,
length,
type,
data
};
}

@ -0,0 +1,65 @@
// 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';
import { IAuthentication } from '../../../../types/Authentication';
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');
}
return buildEAPResponse(identifier, 6, Buffer.from('Password: '));
}
constructor(private authentication: IAuthentication) {}
async handleMessage(
_identifier: number,
stateID: string,
msg: Buffer
): Promise<IPacketHandlerResult> {
const username = 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.
if (!username) {
throw new Error('no username');
}
log('username', username, username.toString());
log('token', token, token.toString());
const success = await this.authentication.authenticate(username.toString(), token.toString());
return {
code: success ? PacketResponseCode.AccessAccept : PacketResponseCode.AccessReject
};
}
}

@ -0,0 +1,40 @@
// 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 { RadiusPacket } from 'radius';
import debug from 'debug';
import { ResponseAuthHandler } from '../../../../types/Handler';
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;
}
export class EAPMD5 implements IEAPMethod {
getEAPType(): number {
return 4;
}
identify(_identifier: number, _stateID: string): IPacketHandlerResult {
// NOT IMPLEMENTED
return {};
}
constructor(private authentication: IAuthentication) {}
async handleMessage(
_identifier: number,
_stateID: string,
_msg: Buffer,
_orgRadiusPacket: RadiusPacket
): Promise<IPacketHandlerResult> {
// not implemented
return {};
}
}

@ -1,19 +1,20 @@
// 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 tls from 'tls';
import * as NodeCache from 'node-cache';
import { RadiusPacket } from 'radius';
import debug from 'debug';
import { encodeTunnelPW, ITLSServer, startTLSServer } from '../../../tls/crypt';
import { ResponseAuthHandler } from '../../../types/Handler';
import { encodeTunnelPW, ITLSServer, startTLSServer } from '../../../../tls/crypt';
import { ResponseAuthHandler } from '../../../../types/Handler';
import { PAPChallenge } from './challenges/PAPChallenge';
import { 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 { 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');
@ -38,6 +39,9 @@ export class EAPTTLS implements IEAPMethod {
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;
}
@ -48,23 +52,23 @@ export class EAPTTLS implements IEAPMethod {
constructor(private authentication: IAuthentication) {}
private buildEAPTTLSResponse(
private buildEAPTTLS(
identifier: number,
msgType = 21,
msgFlags = 0x00,
stateID: string,
data?: Buffer,
newResponse = true
): IPacketHandlerResult {
const maxSize = (MAX_RADIUS_ATTRIBUTE_SIZE - 5) * 4;
newResponse = true,
maxSize = (MAX_RADIUS_ATTRIBUTE_SIZE - 5) * 4
): Buffer {
log('maxSize', maxSize);
/* it's the first one and we have more, therefore include length */
const includeLength = data && newResponse && data.length > maxSize;
const includeLength = maxSize > 0 && data && newResponse && data.length > maxSize;
// extract data party
const dataToSend = data && data.length > 0 && data.slice(0, maxSize);
const dataToQueue = data && data.length > maxSize && data.slice(maxSize);
const dataToSend = maxSize > 0 ? data && data.length > 0 && data.slice(0, maxSize) : data;
const dataToQueue = maxSize > 0 && data && data.length > maxSize && data.slice(maxSize);
/*
0 1 2 3 4 5 6 7 8
@ -129,6 +133,19 @@ export class EAPTTLS implements IEAPMethod {
this.queueData.del(stateID);
}
return resBuffer;
}
private buildEAPTTLSResponse(
identifier: number,
msgType = 21,
msgFlags = 0x00,
stateID: string,
data?: Buffer,
newResponse = true
): IPacketHandlerResult {
const resBuffer = this.buildEAPTTLS(identifier, msgType, msgFlags, stateID, data, newResponse);
const attributes: any = [['State', Buffer.from(stateID)]];
let sentDataSize = 0;
do {
@ -162,7 +179,7 @@ export class EAPTTLS implements IEAPMethod {
Message Length | Data...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
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
@ -191,10 +208,19 @@ export class EAPTTLS implements IEAPMethod {
let msglength;
if (decodedFlags.lengthIncluded) {
msglength = msg.slice(6, 10).readInt32BE(0); // .readDoubleLE(0); // .toString('hex');
msglength = msg.slice(6, 10).readUInt32BE(0); // .readDoubleLE(0); // .toString('hex');
}
const data = msg.slice(decodedFlags.lengthIncluded ? 10 : 6, msg.length);
log('>>>>>>>>>>>> REQUEST FROM CLIENT: EAP TTLS', {
flags: `00000000${flags.toString(2)}`.substr(-8),
decodedFlags,
identifier,
msglength,
data
// dataStr: data.toString()
});
return {
decodedFlags,
msglength,
@ -255,13 +281,10 @@ export class EAPTTLS implements IEAPMethod {
msg: Buffer,
orgRadiusPacket: RadiusPacket
): Promise<IPacketHandlerResult> {
const { decodedFlags, msglength, data } = this.decodeTTLSMessage(msg);
const { data } = this.decodeTTLSMessage(msg);
// check if no data package is there and we have something in the queue, if so.. empty the queue first
if (!data || data.length === 0) {
log(
`>>>>>>>>>>>> REQUEST FROM CLIENT: EAP TTLS, ACK / NACK (no data, just a confirmation, ID: ${identifier})`
);
const queuedData = this.queueData.get(stateID);
if (queuedData instanceof Buffer && queuedData.length > 0) {
return this.buildEAPTTLSResponse(identifier, 21, 0x00, stateID, queuedData, false);
@ -270,15 +293,6 @@ export class EAPTTLS implements IEAPMethod {
return {};
}
log('>>>>>>>>>>>> REQUEST FROM CLIENT: EAP TTLS', {
// flags: `00000000${flags.toString(2)}`.substr(-8),
decodedFlags,
identifier,
msglength
// data,
// dataStr: data.toString()
});
let connection = this.openTLSSockets.get(stateID) as ITLSServer;
if (!connection) {
@ -295,11 +309,18 @@ export class EAPTTLS implements IEAPMethod {
const sendResponsePromise = newDeferredPromise();
const incomingMessageHandler = async (incomingData: Buffer) => {
const type = incomingData.slice(3, 4).readUInt8(0);
const ret: any = {};
ret.attributes = {};
ret.raw_attributes = [];
const { type, data: AVPdata, length: AVPlength } = this.decodeAVP(incomingData);
console.log('AVP data', { AVPdata, AVPlength, AVPdataStr: AVPdata.toString() });
// const code = data.slice(4, 5).readUInt8(0);
switch (type) {
case 1: // PAP / CHAP
case 1: // PAP
try {
const { username, password } = this.papChallenge.decode(incomingData);
const authResult = await this.authentication.authenticate(username, password);
@ -315,17 +336,51 @@ export class EAPTTLS implements IEAPMethod {
sendResponsePromise.resolve(this.buildEAPTTLSResponse(identifier, 3, 0, stateID));
}
break;
default:
case 79: {
const result = await this.tunnelEAP.handlePacket(
{
State: `${stateID}-inner`,
'EAP-Message': AVPdata
},
orgRadiusPacket
);
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,
orgRadiusPacket
)
);
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(79, eapMessage[1]));
break;
}
default: {
log('data', incomingData);
log('data str', incomingData.toString());
// currentConnection!.events.emit('end');
log('UNSUPPORTED AUTH TYPE, requesting identify again (we need PAP!)', type);
log('UNSUPPORTED AUTH TYPE, requesting PAP');
// throw new Error(`unsupported auth type${type}`);
sendResponsePromise.resolve(
this.buildEAPTTLSResponse(identifier, 3, 0, stateID, Buffer.from([1]))
connection.events.emit(
'encrypt',
this.buildAVP(79, this.buildEAPTTLS(identifier, 3, 0, stateID, Buffer.from([1])))
);
}
}
};
@ -341,7 +396,7 @@ export class EAPTTLS implements IEAPMethod {
connection.events.on('response', responseHandler);
// emit data to tls server
connection.events.emit('send', data);
connection.events.emit('decrypt', data);
const responseData = await sendResponsePromise.promise;
// cleanup
@ -351,4 +406,114 @@ export class EAPTTLS implements IEAPMethod {
// send response
return responseData; // this.buildEAPTTLSResponse(identifier, 21, 0x00, stateID, encryptedResponseData);
}
private decodeAVP(buffer: Buffer) {
/**
* 4.1. AVP Header
The fields in the AVP header MUST be sent in network byte order. The
format of the header is:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| AVP Code |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V M P r r r r r| AVP Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Vendor-ID (opt) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 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 length = buffer.slice(5, 8).readUInt16BE(0); // actually a Int24BE
const length = buffer.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);
}
return {
type,
flags: `00000000${flags.toString(2)}`.substr(-8),
decodedFlags,
length,
vendorId,
data
};
}
private buildAVP(
code: number,
data: Buffer,
flags: { VendorSpecific?: boolean; Mandatory?: boolean } = { Mandatory: true }
) {
/**
* 4.1. AVP Header
The fields in the AVP header MUST be sent in network byte order. The
format of the header is:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| AVP Code |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V M r r r r r r| AVP Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Vendor-ID (opt) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data ...
+-+-+-+-+-+-+-+-+
*/
let b = Buffer.alloc(8);
b.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
present and the AVP Code is interpreted according to the namespace
defined by the vendor indicated in the Vendor-ID field.
The 'M' (Mandatory) bit indicates whether support of the AVP is
required. If this bit is set to 0, this indicates that the AVP
may be safely ignored if the receiving party does not understand
or support it. If set to 1, this indicates that the receiving
party MUST fail the negotiation if it does not understand the AVP;
for a TTLS server, this would imply returning EAP-Failure, for a
client, this would imply abandoning the negotiation.
*/
let flagValue = 0;
if (flags.VendorSpecific) {
flagValue += 0b10000000;
}
if (flags.Mandatory) {
flagValue += 0b01000000;
}
console.log('flagValue', flagValue, `00000000${flagValue.toString(2)}`.substr(-8));
b.writeInt8(flagValue, 4); // flags (set V..)
b = Buffer.concat([b, 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)
return b;
}
}

@ -1,5 +1,5 @@
import debug from 'debug';
import { IEAPChallenge } from '../../../../types/EAPChallenge';
import { IEAPChallenge } from '../../../../../types/EAPChallenge';
const log = debug('radius:eap:papchallenge');

@ -42,11 +42,16 @@ export function startTLSServer(): ITLSServer {
});
const encrypted = duplexpair.socket2;
emitter.on('send', (data: Buffer) => {
emitter.on('decrypt', (data: Buffer) => {
encrypted.write(data);
// encrypted.sync();
});
emitter.on('encrypt', (data: Buffer) => {
cleartext.write(data);
// encrypted.sync();
});
encrypted.on('data', (data: Buffer) => {
// log('encrypted data', data, data.toString());
emitter.emit('response', data);

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

@ -4,7 +4,7 @@ import { IPacketHandlerResult } from './PacketHandler';
export interface IEAPMethod {
getEAPType(): number;
identify(identifier: number, stateID: string): IPacketHandlerResult;
identify(identifier: number, stateID: string, msg?: Buffer): IPacketHandlerResult;
handleMessage(
identifier: number,

Loading…
Cancel
Save