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
97ea3fad
Commit
97ea3fad
authored
Jun 25, 2020
by
simon
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix(eap): catch decoding errors
parent
6fc7301c
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
204 additions
and
185 deletions
+204
-185
src/radius/handler/EAPPacketHandler.ts
src/radius/handler/EAPPacketHandler.ts
+89
-84
src/radius/handler/eap/eapMethods/EAP-GTC.ts
src/radius/handler/eap/eapMethods/EAP-GTC.ts
+19
-12
src/radius/handler/eap/eapMethods/EAP-TTLS.ts
src/radius/handler/eap/eapMethods/EAP-TTLS.ts
+96
-89
No files found.
src/radius/handler/EAPPacketHandler.ts
View file @
97ea3fad
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
import
*
as
NodeCache
from
'
node-cache
'
;
import
*
as
NodeCache
from
'
node-cache
'
;
import
debug
from
'
debug
'
;
import
debug
from
'
debug
'
;
import
{
makeid
}
from
'
../../helpers
'
;
import
{
makeid
}
from
'
../../helpers
'
;
import
{
IPacket
,
IPacketHandler
,
IPacketHandlerResult
}
from
'
../../types/PacketHandler
'
;
import
{
IPacket
,
IPacketHandler
,
IPacketHandlerResult
,
PacketResponseCode
}
from
'
../../types/PacketHandler
'
;
import
{
IEAPMethod
}
from
'
../../types/EAPMethod
'
;
import
{
IEAPMethod
}
from
'
../../types/EAPMethod
'
;
import
{
buildEAPResponse
,
decodeEAPHeader
}
from
'
./eap/EAPHelper
'
;
import
{
buildEAPResponse
,
decodeEAPHeader
}
from
'
./eap/EAPHelper
'
;
...
@@ -34,99 +34,104 @@ export class EAPPacketHandler implements IPacketHandler {
...
@@ -34,99 +34,104 @@ export class EAPPacketHandler implements IPacketHandler {
// EAP MESSAGE
// EAP MESSAGE
const
msg
=
packet
.
attributes
[
'
EAP-Message
'
]
as
Buffer
;
const
msg
=
packet
.
attributes
[
'
EAP-Message
'
]
as
Buffer
;
const
{
code
,
type
,
identifier
,
data
}
=
decodeEAPHeader
(
msg
);
try
{
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
[]
};
switch
(
code
)
{
case
1
:
// for request
switch
(
code
)
{
case
2
:
// for response
case
1
:
// for request
switch
(
type
)
{
case
2
:
// for response
case
1
:
// identifiy
switch
(
type
)
{
log
(
'
>>>>>>>>>>>> REQUEST FROM CLIENT: IDENTIFY
'
,
stateID
,
data
.
toString
());
case
1
:
// identifiy
if
(
data
)
{
log
(
'
>>>>>>>>>>>> REQUEST FROM CLIENT: IDENTIFY
'
,
stateID
,
data
.
toString
());
this
.
identities
.
set
(
stateID
,
data
);
// use token til binary 0.);
if
(
data
)
{
}
else
{
this
.
identities
.
set
(
stateID
,
data
);
// use token til binary 0.);
log
(
'
no msg
'
);
}
else
{
}
log
(
'
no msg
'
);
// start identify
if
(
currentState
.
validMethods
.
length
>
0
)
{
return
currentState
.
validMethods
[
0
].
identify
(
identifier
,
stateID
,
data
);
}
return
buildEAPResponse
(
identifier
,
3
);
// NAK
case
2
:
// notification
log
(
'
>>>>>>>>>>>> REQUEST FROM CLIENT: notification
'
,
{});
console
.
info
(
'
notification
'
);
break
;
case
4
:
// md5-challenge
log
(
'
>>>>>>>>>>>> REQUEST FROM CLIENT: md5-challenge
'
,
{});
console
.
info
(
'
md5-challenge
'
);
break
;
case
254
:
// expanded type
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
const
supportedEAPMethods
:
number
[]
=
[];
for
(
const
supportedMethod
of
data
)
{
supportedEAPMethods
.
push
(
supportedMethod
);
}
}
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
// start identify
if
(
currentState
.
validMethods
.
length
>
0
)
{
if
(
currentState
.
validMethods
.
length
>
0
)
{
return
currentState
.
validMethods
[
0
].
identify
(
identifier
,
stateID
,
data
);
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
=
this
.
eapMethods
.
find
((
method
)
=>
{
return
type
===
method
.
getEAPType
();
});
if
(
eapMethod
)
{
return
eapMethod
.
handleMessage
(
identifier
,
stateID
,
msg
,
packet
,
this
.
identities
.
get
(
stateID
)
);
}
// we do not support this auth type, ask for something we support
return
buildEAPResponse
(
identifier
,
3
);
// NAK
const
serverSupportedMethods
=
currentState
.
validMethods
.
map
((
method
)
=>
case
2
:
// notification
method
.
getEAPType
()
log
(
'
>>>>>>>>>>>> REQUEST FROM CLIENT: notification
'
,
{});
);
console
.
info
(
'
notification
'
);
break
;
case
4
:
// md5-challenge
log
(
'
>>>>>>>>>>>> REQUEST FROM CLIENT: md5-challenge
'
,
{});
console
.
info
(
'
md5-challenge
'
);
break
;
case
254
:
// expanded type
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
const
supportedEAPMethods
:
number
[]
=
[];
for
(
const
supportedMethod
of
data
)
{
supportedEAPMethods
.
push
(
supportedMethod
);
}
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
=
this
.
eapMethods
.
find
((
method
)
=>
{
return
type
===
method
.
getEAPType
();
});
if
(
eapMethod
)
{
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
()
);
console
.
error
(
'
unsupported type
'
,
type
,
`requesting:
${
serverSupportedMethods
}
`
);
console
.
error
(
'
unsupported type
'
,
type
,
`requesting:
${
serverSupportedMethods
}
`
);
return
buildEAPResponse
(
identifier
,
3
,
Buffer
.
from
(
serverSupportedMethods
));
return
buildEAPResponse
(
identifier
,
3
,
Buffer
.
from
(
serverSupportedMethods
));
}
}
}
}
break
;
break
;
case
3
:
case
3
:
log
(
'
Client Auth Success
'
);
log
(
'
Client Auth Success
'
);
break
;
break
;
case
4
:
case
4
:
log
(
'
Client Auth FAILURE
'
);
log
(
'
Client Auth FAILURE
'
);
break
;
break
;
default
:
default
:
}
// silently ignore;
return
{};
}
catch
(
err
)
{
console
.
error
(
'
decoding of (generic) EAP package failed
'
,
msg
,
err
);
return
{};
}
}
// silently ignore;
return
{};
}
}
}
}
src/radius/handler/eap/eapMethods/EAP-GTC.ts
View file @
97ea3fad
...
@@ -37,22 +37,29 @@ export class EAPGTC implements IEAPMethod {
...
@@ -37,22 +37,29 @@ export class EAPGTC implements IEAPMethod {
):
Promise
<
IPacketHandlerResult
>
{
):
Promise
<
IPacketHandlerResult
>
{
const
username
=
identity
;
// this.loginData.get(stateID) as Buffer | undefined;
const
username
=
identity
;
// this.loginData.get(stateID) as Buffer | undefined;
const
{
data
}
=
decodeEAPHeader
(
msg
);
try
{
const
{
data
}
=
decodeEAPHeader
(
msg
);
const
token
=
this
.
extractValue
(
data
);
const
token
=
this
.
extractValue
(
data
);
if
(
!
username
)
{
if
(
!
username
)
{
throw
new
Error
(
'
no username
'
);
throw
new
Error
(
'
no username
'
);
}
}
log
(
'
username
'
,
username
,
username
.
toString
());
log
(
'
username
'
,
username
,
username
.
toString
());
log
(
'
token
'
,
token
,
token
.
toString
());
log
(
'
token
'
,
token
,
token
.
toString
());
const
success
=
await
this
.
authentication
.
authenticate
(
username
.
toString
(),
token
.
toString
());
const
success
=
await
this
.
authentication
.
authenticate
(
username
.
toString
(),
token
.
toString
());
return
{
return
{
code
:
success
?
PacketResponseCode
.
AccessAccept
:
PacketResponseCode
.
AccessReject
,
code
:
success
?
PacketResponseCode
.
AccessAccept
:
PacketResponseCode
.
AccessReject
,
attributes
:
(
success
&&
[[
'
User-Name
'
,
username
]])
||
undefined
,
attributes
:
(
success
&&
[[
'
User-Name
'
,
username
]])
||
undefined
,
};
};
}
catch
(
err
)
{
console
.
error
(
'
decoding of EAP-GTC package failed
'
,
msg
,
err
);
return
{
code
:
PacketResponseCode
.
AccessReject
,
};
}
}
}
}
}
src/radius/handler/eap/eapMethods/EAP-TTLS.ts
View file @
97ea3fad
...
@@ -300,113 +300,120 @@ export class EAPTTLS implements IEAPMethod {
...
@@ -300,113 +300,120 @@ export class EAPTTLS implements IEAPMethod {
return
{};
return
{};
}
}
this
.
lastProcessedIdentifier
.
set
(
stateID
,
identifier
);
this
.
lastProcessedIdentifier
.
set
(
stateID
,
identifier
);
const
{
data
}
=
this
.
decodeTTLSMessage
(
msg
);
try
{
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
)
{
// check if no data package is there and we have something in the queue, if so.. empty the queue first
const
queuedData
=
this
.
queueData
.
get
(
stateID
);
if
(
!
data
||
data
.
length
===
0
)
{
if
(
queuedData
instanceof
Buffer
&&
queuedData
.
length
>
0
)
{
const
queuedData
=
this
.
queueData
.
get
(
stateID
);
log
(
`returning queued data for
${
stateID
}
`
);
if
(
queuedData
instanceof
Buffer
&&
queuedData
.
length
>
0
)
{
return
this
.
buildEAPTTLSResponse
(
identifier
,
21
,
0x00
,
stateID
,
queuedData
,
false
);
log
(
`returning queued data for
${
stateID
}
`
);
return
this
.
buildEAPTTLSResponse
(
identifier
,
21
,
0x00
,
stateID
,
queuedData
,
false
);
}
log
(
`empty data queue for
${
stateID
}
`
);
return
{};
}
}
log
(
`empty data queue for
${
stateID
}
`
);
let
connection
=
this
.
openTLSSockets
.
get
(
stateID
)
as
ITLSServer
;
return
{};
}
let
connection
=
this
.
openTLSSockets
.
get
(
stateID
)
as
ITLSServer
;
if
(
!
connection
)
{
if
(
!
connection
)
{
connection
=
startTLSServer
();
connection
=
startTLSServer
();
this
.
openTLSSockets
.
set
(
stateID
,
connection
);
this
.
openTLSSockets
.
set
(
stateID
,
connection
);
connection
.
events
.
on
(
'
end
'
,
()
=>
{
connection
.
events
.
on
(
'
end
'
,
()
=>
{
// cleanup socket
// cleanup socket
log
(
'
ENDING SOCKET
'
);
log
(
'
ENDING SOCKET
'
);
this
.
openTLSSockets
.
del
(
stateID
);
this
.
openTLSSockets
.
del
(
stateID
);
});
});
}
}
const
sendResponsePromise
=
newDeferredPromise
();
const
sendResponsePromise
=
newDeferredPromise
();
const
incomingMessageHandler
=
async
(
incomingData
:
Buffer
)
=>
{
const
incomingMessageHandler
=
async
(
incomingData
:
Buffer
)
=>
{
const
ret
:
any
=
{};
const
ret
:
any
=
{};
ret
.
attributes
=
{};
ret
.
attributes
=
{};
ret
.
raw_attributes
=
[];
ret
.
raw_attributes
=
[];
const
AVPs
=
this
.
decodeAVPs
(
incomingData
);
const
AVPs
=
this
.
decodeAVPs
(
incomingData
);
// build attributes for packet handler
// build attributes for packet handler
const
attributes
:
IPacketAttributes
=
{};
const
attributes
:
IPacketAttributes
=
{};
AVPs
.
forEach
((
avp
)
=>
{
AVPs
.
forEach
((
avp
)
=>
{
attributes
[
attr_id_to_name
(
avp
.
type
)]
=
avp
.
data
;
attributes
[
attr_id_to_name
(
avp
.
type
)]
=
avp
.
data
;
});
});
attributes
.
State
=
`
${
stateID
}
-inner`
;
attributes
.
State
=
`
${
stateID
}
-inner`
;
// handle incoming package via inner tunnel
// handle incoming package via inner tunnel
const
result
=
await
this
.
innerTunnel
.
handlePacket
(
const
result
=
await
this
.
innerTunnel
.
handlePacket
(
{
{
attributes
,
attributes
,
},
},
this
.
getEAPType
()
this
.
getEAPType
()
);
);
log
(
'
inner tunnel result
'
,
result
);
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
)
);
};
if
(
const
responseHandler
=
(
encryptedResponseData
:
Buffer
)
=>
{
result
.
code
===
PacketResponseCode
.
AccessReject
||
// send back...
result
.
code
===
PacketResponseCode
.
AccessAccept
)
{
sendResponsePromise
.
resolve
(
sendResponsePromise
.
resolve
(
this
.
authResponse
(
this
.
buildEAPTTLSResponse
(
identifier
,
21
,
0x00
,
stateID
,
encryptedResponseData
)
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
)
);
};
const
responseHandler
=
(
encryptedResponseData
:
Buffer
)
=>
{
// send back...
sendResponsePromise
.
resolve
(
this
.
buildEAPTTLSResponse
(
identifier
,
21
,
0x00
,
stateID
,
encryptedResponseData
)
);
};
// register event listeners
// register event listeners
connection
.
events
.
on
(
'
incoming
'
,
incomingMessageHandler
);
connection
.
events
.
on
(
'
incoming
'
,
incomingMessageHandler
);
connection
.
events
.
on
(
'
response
'
,
responseHandler
);
connection
.
events
.
on
(
'
response
'
,
responseHandler
);
// emit data to tls server
// emit data to tls server
connection
.
events
.
emit
(
'
decrypt
'
,
data
);
connection
.
events
.
emit
(
'
decrypt
'
,
data
);
const
responseData
=
await
sendResponsePromise
.
promise
;
const
responseData
=
await
sendResponsePromise
.
promise
;
// cleanup
// cleanup
connection
.
events
.
off
(
'
incoming
'
,
incomingMessageHandler
);
connection
.
events
.
off
(
'
incoming
'
,
incomingMessageHandler
);
connection
.
events
.
off
(
'
response
'
,
responseHandler
);
connection
.
events
.
off
(
'
response
'
,
responseHandler
);
// send response
// send response
return
responseData
;
// this.buildEAPTTLSResponse(identifier, 21, 0x00, stateID, encryptedResponseData);
return
responseData
;
// this.buildEAPTTLSResponse(identifier, 21, 0x00, stateID, encryptedResponseData);
}
catch
(
err
)
{
console
.
error
(
'
decoding of EAP-TTLS package failed
'
,
msg
,
err
);
return
{
code
:
PacketResponseCode
.
AccessReject
,
};
}
}
}
private
transformAttributesArrayToMap
(
attributes
:
[
string
,
Buffer
|
string
][]
|
undefined
)
{
private
transformAttributesArrayToMap
(
attributes
:
[
string
,
Buffer
|
string
][]
|
undefined
)
{
...
...
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