Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
N
Node Radius Server
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nanahira
Node Radius Server
Commits
6aa4b9f9
Commit
6aa4b9f9
authored
Feb 24, 2020
by
simon
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: inner tunnel for TTSL support added
parent
191bb542
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
419 additions
and
136 deletions
+419
-136
src/auth.ts
src/auth.ts
+1
-0
src/auth/GoogleLDAPAuth.ts
src/auth/GoogleLDAPAuth.ts
+1
-1
src/radius/RadiusService.ts
src/radius/RadiusService.ts
+11
-1
src/radius/handler/EAPPacketHandler.ts
src/radius/handler/EAPPacketHandler.ts
+9
-91
src/radius/handler/eap/EAPHelper.ts
src/radius/handler/eap/EAPHelper.ts
+79
-0
src/radius/handler/eap/eapMethods/EAP-GTC.ts
src/radius/handler/eap/eapMethods/EAP-GTC.ts
+65
-0
src/radius/handler/eap/eapMethods/EAP-MD5.ts
src/radius/handler/eap/eapMethods/EAP-MD5.ts
+40
-0
src/radius/handler/eap/eapMethods/EAP-TTLS.ts
src/radius/handler/eap/eapMethods/EAP-TTLS.ts
+204
-39
src/radius/handler/eap/eapMethods/EAP.ts
src/radius/handler/eap/eapMethods/EAP.ts
+0
-0
src/radius/handler/eap/eapMethods/challenges/PAPChallenge.ts
src/radius/handler/eap/eapMethods/challenges/PAPChallenge.ts
+1
-1
src/tls/crypt.ts
src/tls/crypt.ts
+6
-1
src/types/EAPChallenge.ts
src/types/EAPChallenge.ts
+1
-1
src/types/EAPMethod.ts
src/types/EAPMethod.ts
+1
-1
No files found.
src/auth.ts
View file @
6aa4b9f9
...
@@ -18,6 +18,7 @@ export class Authentication implements IAuthentication {
...
@@ -18,6 +18,7 @@ export class Authentication implements IAuthentication {
}
}
const
authResult
=
await
this
.
authenticator
.
authenticate
(
username
,
password
);
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
this
.
cache
.
set
(
cacheKey
,
authResult
,
86400
);
// cache for one day
return
authResult
;
return
authResult
;
...
...
src/auth/GoogleLDAPAuth.ts
View file @
6aa4b9f9
...
@@ -113,7 +113,7 @@ export class GoogleLDAPAuth implements IAuthentication {
...
@@ -113,7 +113,7 @@ export class GoogleLDAPAuth implements IAuthentication {
if (!dnsFetched && !forceFetching) {
if (!dnsFetched && !forceFetching) {
return this.authenticate(username, password, count, true);
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
;
return
false
;
}
}
...
...
src/radius/RadiusService.ts
View file @
6aa4b9f9
...
@@ -4,11 +4,21 @@ import { EAPPacketHandler } from './handler/EAPPacketHandler';
...
@@ -4,11 +4,21 @@ import { EAPPacketHandler } from './handler/EAPPacketHandler';
import
{
DefaultPacketHandler
}
from
'
./handler/DefaultPacketHandler
'
;
import
{
DefaultPacketHandler
}
from
'
./handler/DefaultPacketHandler
'
;
import
{
IPacketHandler
,
IPacketHandlerResult
,
PacketResponseCode
}
from
'
../types/PacketHandler
'
;
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
{
export
class
RadiusService
{
radiusPacketHandlers
:
IPacketHandler
[]
=
[];
radiusPacketHandlers
:
IPacketHandler
[]
=
[];
constructor
(
private
secret
:
string
,
private
authentication
:
IAuthentication
)
{
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
));
this
.
radiusPacketHandlers
.
push
(
new
DefaultPacketHandler
(
authentication
));
}
}
...
...
src/radius/handler/EAPPacketHandler.ts
View file @
6aa4b9f9
...
@@ -3,103 +3,21 @@
...
@@ -3,103 +3,21 @@
import
*
as
NodeCache
from
'
node-cache
'
;
import
*
as
NodeCache
from
'
node-cache
'
;
import
{
RadiusPacket
}
from
'
radius
'
;
import
{
RadiusPacket
}
from
'
radius
'
;
import
debug
from
'
debug
'
;
import
debug
from
'
debug
'
;
import
{
EAPTTLS
}
from
'
./eapMethods/EAPTTLS
'
;
import
{
makeid
}
from
'
../../helpers
'
;
import
{
makeid
}
from
'
../../helpers
'
;
import
{
import
{
IPacketHandler
,
IPacketHandlerResult
}
from
'
../../types/PacketHandler
'
;
IPacketHandler
,
IPacketHandlerResult
,
PacketResponseCode
}
from
'
../../types/PacketHandler
'
;
import
{
IAuthentication
}
from
'
../../types/Authentication
'
;
import
{
IEAPMethod
}
from
'
../../types/EAPMethod
'
;
import
{
IEAPMethod
}
from
'
../../types/EAPMethod
'
;
import
{
buildEAPResponse
,
decodeEAPHeader
}
from
'
./eap/EAPHelper
'
;
const
log
=
debug
(
'
radius:eap
'
);
const
log
=
debug
(
'
radius:eap
'
);
export
class
EAPPacketHandler
implements
IPacketHandler
{
export
class
EAPPacketHandler
implements
IPacketHandler
{
private
eapMethods
:
IEAPMethod
[]
=
[];
// private eapConnectionStates: { [key: string]: { validMethods: IEAPMethod[] } } = {};
// private eapConnectionStates: { [key: string]: { validMethods: IEAPMethod[] } } = {};
private
eapConnectionStates
=
new
NodeCache
({
useClones
:
false
,
stdTTL
:
3600
});
// max for one hour
private
eapConnectionStates
=
new
NodeCache
({
useClones
:
false
,
stdTTL
:
3600
});
// max for one hour
constructor
(
authentication
:
IAuthentication
)
{
constructor
(
private
eapMethods
:
IEAPMethod
[])
{}
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
};
}
async
handlePacket
(
async
handlePacket
(
attributes
:
{
[
key
:
string
]:
Buffer
},
attributes
:
{
[
key
:
string
]:
Buffer
|
string
},
orgRadiusPacket
:
RadiusPacket
orgRadiusPacket
:
RadiusPacket
):
Promise
<
IPacketHandlerResult
>
{
):
Promise
<
IPacketHandlerResult
>
{
if
(
!
attributes
[
'
EAP-Message
'
])
{
if
(
!
attributes
[
'
EAP-Message
'
])
{
...
@@ -116,9 +34,9 @@ export class EAPPacketHandler implements IPacketHandler {
...
@@ -116,9 +34,9 @@ export class EAPPacketHandler implements IPacketHandler {
}
}
// EAP MESSAGE
// 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
[]
};
const
currentState
=
this
.
eapConnectionStates
.
get
(
stateID
)
as
{
validMethods
:
IEAPMethod
[]
};
...
@@ -130,10 +48,10 @@ export class EAPPacketHandler implements IPacketHandler {
...
@@ -130,10 +48,10 @@ export class EAPPacketHandler implements IPacketHandler {
log
(
'
>>>>>>>>>>>> REQUEST FROM CLIENT: IDENTIFY
'
,
{});
log
(
'
>>>>>>>>>>>> REQUEST FROM CLIENT: IDENTIFY
'
,
{});
// start identify
// start identify
if
(
currentState
.
validMethods
.
length
>
0
)
{
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
case
2
:
// notification
log
(
'
>>>>>>>>>>>> REQUEST FROM CLIENT: notification
'
,
{});
log
(
'
>>>>>>>>>>>> REQUEST FROM CLIENT: notification
'
,
{});
console
.
info
(
'
notification
'
);
console
.
info
(
'
notification
'
);
...
@@ -180,7 +98,7 @@ export class EAPPacketHandler implements IPacketHandler {
...
@@ -180,7 +98,7 @@ export class EAPPacketHandler implements IPacketHandler {
console
.
error
(
'
unsupported type
'
,
type
,
`requesting:
${
serverSupportedMethods
}
`
);
console
.
error
(
'
unsupported type
'
,
type
,
`requesting:
${
serverSupportedMethods
}
`
);
return
this
.
buildEAPResponse
(
identifier
,
3
,
Buffer
.
from
(
serverSupportedMethods
));
return
buildEAPResponse
(
identifier
,
3
,
Buffer
.
from
(
serverSupportedMethods
));
}
}
}
}
break
;
break
;
...
...
src/radius/handler/eap/EAPHelper.ts
0 → 100644
View file @
6aa4b9f9
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
};
}
src/radius/handler/eap/eapMethods/EAP-GTC.ts
0 → 100644
View file @
6aa4b9f9
// 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
};
}
}
src/radius/handler/eap/eapMethods/EAP-MD5.ts
0 → 100644
View file @
6aa4b9f9
// 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
{};
}
}
src/radius/handler/eap
Methods/EAP
TTLS.ts
→
src/radius/handler/eap
/eapMethods/EAP-
TTLS.ts
View file @
6aa4b9f9
// https://tools.ietf.org/html/rfc5281 TTLS v0
// https://tools.ietf.org/html/rfc5281 TTLS v0
// 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)
/* eslint-disable no-bitwise */
/* eslint-disable no-bitwise */
import
*
as
tls
from
'
tls
'
;
import
*
as
tls
from
'
tls
'
;
import
*
as
NodeCache
from
'
node-cache
'
;
import
*
as
NodeCache
from
'
node-cache
'
;
import
{
RadiusPacket
}
from
'
radius
'
;
import
{
RadiusPacket
}
from
'
radius
'
;
import
debug
from
'
debug
'
;
import
debug
from
'
debug
'
;
import
{
encodeTunnelPW
,
ITLSServer
,
startTLSServer
}
from
'
../../../tls/crypt
'
;
import
{
encodeTunnelPW
,
ITLSServer
,
startTLSServer
}
from
'
../../../
../
tls/crypt
'
;
import
{
ResponseAuthHandler
}
from
'
../../../types/Handler
'
;
import
{
ResponseAuthHandler
}
from
'
../../../
../
types/Handler
'
;
import
{
PAPChallenge
}
from
'
./challenges/PAPChallenge
'
;
import
{
PAPChallenge
}
from
'
./challenges/PAPChallenge
'
;
import
{
IPacketHandlerResult
,
PacketResponseCode
}
from
'
../../../types/PacketHandler
'
;
import
{
IPacketHandlerResult
,
PacketResponseCode
}
from
'
../../../../types/PacketHandler
'
;
import
{
MAX_RADIUS_ATTRIBUTE_SIZE
,
newDeferredPromise
}
from
'
../../../helpers
'
;
import
{
MAX_RADIUS_ATTRIBUTE_SIZE
,
newDeferredPromise
}
from
'
../../../../helpers
'
;
import
{
IEAPMethod
}
from
'
../../../types/EAPMethod
'
;
import
{
IEAPMethod
}
from
'
../../../../types/EAPMethod
'
;
import
{
IAuthentication
}
from
'
../../../types/Authentication
'
;
import
{
IAuthentication
}
from
'
../../../../types/Authentication
'
;
import
{
secret
}
from
'
../../../../config
'
;
import
{
secret
}
from
'
../../../../../config
'
;
import
{
EAPPacketHandler
}
from
'
../../EAPPacketHandler
'
;
import
{
EAPGTC
}
from
'
./EAP-GTC
'
;
const
log
=
debug
(
'
radius:eap:ttls
'
);
const
log
=
debug
(
'
radius:eap:ttls
'
);
...
@@ -38,6 +39,9 @@ export class EAPTTLS implements IEAPMethod {
...
@@ -38,6 +39,9 @@ export class EAPTTLS implements IEAPMethod {
private
openTLSSockets
=
new
NodeCache
({
useClones
:
false
,
stdTTL
:
3600
});
// keep sockets for about one hour
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
{
getEAPType
():
number
{
return
21
;
return
21
;
}
}
...
@@ -48,23 +52,23 @@ export class EAPTTLS implements IEAPMethod {
...
@@ -48,23 +52,23 @@ export class EAPTTLS implements IEAPMethod {
constructor
(
private
authentication
:
IAuthentication
)
{}
constructor
(
private
authentication
:
IAuthentication
)
{}
private
buildEAPTTLS
Response
(
private
buildEAPTTLS
(
identifier
:
number
,
identifier
:
number
,
msgType
=
21
,
msgType
=
21
,
msgFlags
=
0x00
,
msgFlags
=
0x00
,
stateID
:
string
,
stateID
:
string
,
data
?:
Buffer
,
data
?:
Buffer
,
newResponse
=
true
newResponse
=
true
,
):
IPacketHandlerResult
{
maxSize
=
(
MAX_RADIUS_ATTRIBUTE_SIZE
-
5
)
*
4
const
maxSize
=
(
MAX_RADIUS_ATTRIBUTE_SIZE
-
5
)
*
4
;
):
Buffer
{
log
(
'
maxSize
'
,
maxSize
);
log
(
'
maxSize
'
,
maxSize
);
/* it's the first one and we have more, therefore include length */
/* 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
// extract data party
const
dataToSend
=
data
&&
data
.
length
>
0
&&
data
.
slice
(
0
,
maxSize
)
;
const
dataToSend
=
maxSize
>
0
?
data
&&
data
.
length
>
0
&&
data
.
slice
(
0
,
maxSize
)
:
data
;
const
dataToQueue
=
data
&&
data
.
length
>
maxSize
&&
data
.
slice
(
maxSize
);
const
dataToQueue
=
maxSize
>
0
&&
data
&&
data
.
length
>
maxSize
&&
data
.
slice
(
maxSize
);
/*
/*
0 1 2 3 4 5 6 7 8
0 1 2 3 4 5 6 7 8
...
@@ -129,6 +133,19 @@ export class EAPTTLS implements IEAPMethod {
...
@@ -129,6 +133,19 @@ export class EAPTTLS implements IEAPMethod {
this
.
queueData
.
del
(
stateID
);
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
)]];
const
attributes
:
any
=
[[
'
State
'
,
Buffer
.
from
(
stateID
)]];
let
sentDataSize
=
0
;
let
sentDataSize
=
0
;
do
{
do
{
...
@@ -162,7 +179,7 @@ export class EAPTTLS implements IEAPMethod {
...
@@ -162,7 +179,7 @@ export class EAPTTLS implements IEAPMethod {
Message Length | Data...
Message Length | Data...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
*/
const
identifier
=
msg
.
slice
(
1
,
2
).
readUInt8
(
0
);
const
flags
=
msg
.
slice
(
5
,
6
).
readUInt8
(
0
);
// .toString('hex');
const
flags
=
msg
.
slice
(
5
,
6
).
readUInt8
(
0
);
// .toString('hex');
/*
/*
0 1 2 3 4 5 6 7
0 1 2 3 4 5 6 7
...
@@ -191,10 +208,19 @@ export class EAPTTLS implements IEAPMethod {
...
@@ -191,10 +208,19 @@ export class EAPTTLS implements IEAPMethod {
let
msglength
;
let
msglength
;
if
(
decodedFlags
.
lengthIncluded
)
{
if
(
decodedFlags
.
lengthIncluded
)
{
msglength
=
msg
.
slice
(
6
,
10
).
readInt32BE
(
0
);
// .readDoubleLE(0); // .toString('hex');
msglength
=
msg
.
slice
(
6
,
10
).
read
U
Int32BE
(
0
);
// .readDoubleLE(0); // .toString('hex');
}
}
const
data
=
msg
.
slice
(
decodedFlags
.
lengthIncluded
?
10
:
6
,
msg
.
length
);
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
{
return
{
decodedFlags
,
decodedFlags
,
msglength
,
msglength
,
...
@@ -255,13 +281,10 @@ export class EAPTTLS implements IEAPMethod {
...
@@ -255,13 +281,10 @@ export class EAPTTLS implements IEAPMethod {
msg
:
Buffer
,
msg
:
Buffer
,
orgRadiusPacket
:
RadiusPacket
orgRadiusPacket
:
RadiusPacket
):
Promise
<
IPacketHandlerResult
>
{
):
Promise
<
IPacketHandlerResult
>
{
const
{
d
ecodedFlags
,
msglength
,
d
ata
}
=
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
// 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
)
{
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
);
const
queuedData
=
this
.
queueData
.
get
(
stateID
);
if
(
queuedData
instanceof
Buffer
&&
queuedData
.
length
>
0
)
{
if
(
queuedData
instanceof
Buffer
&&
queuedData
.
length
>
0
)
{
return
this
.
buildEAPTTLSResponse
(
identifier
,
21
,
0x00
,
stateID
,
queuedData
,
false
);
return
this
.
buildEAPTTLSResponse
(
identifier
,
21
,
0x00
,
stateID
,
queuedData
,
false
);
...
@@ -270,15 +293,6 @@ export class EAPTTLS implements IEAPMethod {
...
@@ -270,15 +293,6 @@ export class EAPTTLS implements IEAPMethod {
return
{};
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
;
let
connection
=
this
.
openTLSSockets
.
get
(
stateID
)
as
ITLSServer
;
if
(
!
connection
)
{
if
(
!
connection
)
{
...
@@ -295,11 +309,18 @@ export class EAPTTLS implements IEAPMethod {
...
@@ -295,11 +309,18 @@ export class EAPTTLS implements IEAPMethod {
const
sendResponsePromise
=
newDeferredPromise
();
const
sendResponsePromise
=
newDeferredPromise
();
const
incomingMessageHandler
=
async
(
incomingData
:
Buffer
)
=>
{
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);
// const code = data.slice(4, 5).readUInt8(0);
switch
(
type
)
{
switch
(
type
)
{
case
1
:
// PAP
/ CHAP
case
1
:
// PAP
try
{
try
{
const
{
username
,
password
}
=
this
.
papChallenge
.
decode
(
incomingData
);
const
{
username
,
password
}
=
this
.
papChallenge
.
decode
(
incomingData
);
const
authResult
=
await
this
.
authentication
.
authenticate
(
username
,
password
);
const
authResult
=
await
this
.
authentication
.
authenticate
(
username
,
password
);
...
@@ -315,17 +336,51 @@ export class EAPTTLS implements IEAPMethod {
...
@@ -315,17 +336,51 @@ export class EAPTTLS implements IEAPMethod {
sendResponsePromise
.
resolve
(
this
.
buildEAPTTLSResponse
(
identifier
,
3
,
0
,
stateID
));
sendResponsePromise
.
resolve
(
this
.
buildEAPTTLSResponse
(
identifier
,
3
,
0
,
stateID
));
}
}
break
;
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
'
,
incomingData
);
log
(
'
data str
'
,
incomingData
.
toString
());
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
'
);
connection
.
events
.
emit
(
// throw new Error(`unsupported auth type${type}`);
'
encrypt
'
,
sendResponsePromise
.
resolve
(
this
.
buildAVP
(
79
,
this
.
buildEAPTTLS
(
identifier
,
3
,
0
,
stateID
,
Buffer
.
from
([
1
])))
this
.
buildEAPTTLSResponse
(
identifier
,
3
,
0
,
stateID
,
Buffer
.
from
([
1
]))
);
);
}
}
}
};
};
...
@@ -341,7 +396,7 @@ export class EAPTTLS implements IEAPMethod {
...
@@ -341,7 +396,7 @@ export class EAPTTLS implements IEAPMethod {
connection
.
events
.
on
(
'
response
'
,
responseHandler
);
connection
.
events
.
on
(
'
response
'
,
responseHandler
);
// emit data to tls server
// emit data to tls server
connection
.
events
.
emit
(
'
send
'
,
data
);
connection
.
events
.
emit
(
'
decrypt
'
,
data
);
const
responseData
=
await
sendResponsePromise
.
promise
;
const
responseData
=
await
sendResponsePromise
.
promise
;
// cleanup
// cleanup
...
@@ -351,4 +406,114 @@ export class EAPTTLS implements IEAPMethod {
...
@@ -351,4 +406,114 @@ export class EAPTTLS implements IEAPMethod {
// send response
// send response
return
responseData
;
// this.buildEAPTTLSResponse(identifier, 21, 0x00, stateID, encryptedResponseData);
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
;
}
}
}
src/radius/handler/eap/eapMethods/EAP.ts
0 → 100644
View file @
6aa4b9f9
src/radius/handler/eapMethods/challenges/PAPChallenge.ts
→
src/radius/handler/eap
/eap
Methods/challenges/PAPChallenge.ts
View file @
6aa4b9f9
import
debug
from
'
debug
'
;
import
debug
from
'
debug
'
;
import
{
IEAPChallenge
}
from
'
../../../../types/EAPChallenge
'
;
import
{
IEAPChallenge
}
from
'
../../../../
../
types/EAPChallenge
'
;
const
log
=
debug
(
'
radius:eap:papchallenge
'
);
const
log
=
debug
(
'
radius:eap:papchallenge
'
);
...
...
src/tls/crypt.ts
View file @
6aa4b9f9
...
@@ -42,11 +42,16 @@ export function startTLSServer(): ITLSServer {
...
@@ -42,11 +42,16 @@ export function startTLSServer(): ITLSServer {
});
});
const
encrypted
=
duplexpair
.
socket2
;
const
encrypted
=
duplexpair
.
socket2
;
emitter
.
on
(
'
send
'
,
(
data
:
Buffer
)
=>
{
emitter
.
on
(
'
decrypt
'
,
(
data
:
Buffer
)
=>
{
encrypted
.
write
(
data
);
encrypted
.
write
(
data
);
// encrypted.sync();
// encrypted.sync();
});
});
emitter
.
on
(
'
encrypt
'
,
(
data
:
Buffer
)
=>
{
cleartext
.
write
(
data
);
// encrypted.sync();
});
encrypted
.
on
(
'
data
'
,
(
data
:
Buffer
)
=>
{
encrypted
.
on
(
'
data
'
,
(
data
:
Buffer
)
=>
{
// log('encrypted data', data, data.toString());
// log('encrypted data', data, data.toString());
emitter
.
emit
(
'
response
'
,
data
);
emitter
.
emit
(
'
response
'
,
data
);
...
...
src/types/EAPChallenge.ts
View file @
6aa4b9f9
export
interface
IEAPChallenge
{
export
interface
IEAPChallenge
{
decode
(
data
:
Buffer
):
{
username
:
string
;
password
:
string
};
decode
(
data
:
Buffer
,
stateID
:
string
):
{
username
:
string
;
password
?
:
string
};
}
}
src/types/EAPMethod.ts
View file @
6aa4b9f9
...
@@ -4,7 +4,7 @@ import { IPacketHandlerResult } from './PacketHandler';
...
@@ -4,7 +4,7 @@ import { IPacketHandlerResult } from './PacketHandler';
export
interface
IEAPMethod
{
export
interface
IEAPMethod
{
getEAPType
():
number
;
getEAPType
():
number
;
identify
(
identifier
:
number
,
stateID
:
string
):
IPacketHandlerResult
;
identify
(
identifier
:
number
,
stateID
:
string
,
msg
?:
Buffer
):
IPacketHandlerResult
;
handleMessage
(
handleMessage
(
identifier
:
number
,
identifier
:
number
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment