MFA authentication of VPN clients by router via

Dear community,

please accept my apologies for the following ingenuous question.

I have installed privacyIDEA 3.4.1 incl. FreeRADIUS and the respective module.

Using radclient I can authenticate my users successfully.

My scenario is as follows:

I added a VPN IKEv2 connection to my router with RSA signature for local authentication (using a certificate) and with EAP for remote authentication via Radius.

The VPN client of the road warrior is configured with IKEv2 authentication EAP, the local identity is a Fully Qualified Username with UserName & Password as EAP authentication. In addition to that the client holds a local copy of the Root CA certificate of the afore mentioned VPN connection certificate.

Here is the radius output if I try to connect the client:

(1) Received Access-Request Id 40 from to length 123
(1)   User-Name = "flhe@domain.internal"
(1)   Calling-Station-Id = ""
(1)   NAS-IP-Address =
(1)   EAP-Message = 0x02a1001d01666c6865406d65696572736572766963652e6f6666696365
(1)   Message-Authenticator = 0x916c9e5c3756daa1a354927ecec083df
(1)   Service-Type = Login-User
(1) # Executing section authorize from file /etc/raddb/sites-enabled/privacyidea
(1)   authorize {
(1)     [files] = noop
(1) perl:   $RAD_REQUEST{'User-Name'} = &request:User-Name -> 'flhe@domain.internal'
(1) perl:   $RAD_REQUEST{'NAS-IP-Address'} = &request:NAS-IP-Address -> ''
(1) perl:   $RAD_REQUEST{'Service-Type'} = &request:Service-Type -> 'Login-User'
(1) perl:   $RAD_REQUEST{'Calling-Station-Id'} = &request:Calling-Station-Id -> ''
(1) perl:   $RAD_REQUEST{'EAP-Message'} = &request:EAP-Message -> '0x02a1001d01666c6865406d65696572736572766963652e6f6666696365'
(1) perl:   $RAD_REQUEST{'Message-Authenticator'} = &request:Message-Authenticator -> '0x916c9e5c3756daa1a354927ecec083df'
(1) perl: &request:User-Name = $RAD_REQUEST{'User-Name'} -> 'flhe@domain.internal'
(1) perl: &request:Service-Type = $RAD_REQUEST{'Service-Type'} -> 'Login-User'
(1) perl: &request:Message-Authenticator = $RAD_REQUEST{'Message-Authenticator'} -> '0x916c9e5c3756daa1a354927ecec083df'
(1) perl: &request:EAP-Message = $RAD_REQUEST{'EAP-Message'} -> '0x02a1001d01666c6865406d65696572736572766963652e6f6666696365'
(1) perl: &request:Calling-Station-Id = $RAD_REQUEST{'Calling-Station-Id'} -> ''
(1) perl: &request:NAS-IP-Address = $RAD_REQUEST{'NAS-IP-Address'} -> ''
(1)     [perl] = ok
(1)     if (ok || updated) {
(1)     if (ok || updated)  -> TRUE
(1)     if (ok || updated)  {
(1)       update control {
(1)         Auth-Type := Perl
(1)       } # update control = noop
(1)     } # if (ok || updated)  = noop
(1)   } # authorize = ok
(1) Found Auth-Type = Perl
(1) # Executing group from file /etc/raddb/sites-enabled/privacyidea
(1)   Auth-Type Perl {
(1) perl:   $RAD_REQUEST{'User-Name'} = &request:User-Name -> 'flhe@domain.internal'
(1) perl:   $RAD_REQUEST{'NAS-IP-Address'} = &request:NAS-IP-Address -> ''
(1) perl:   $RAD_REQUEST{'Service-Type'} = &request:Service-Type -> 'Login-User'
(1) perl:   $RAD_REQUEST{'Calling-Station-Id'} = &request:Calling-Station-Id -> ''
(1) perl:   $RAD_REQUEST{'EAP-Message'} = &request:EAP-Message -> '0x02a1001d01666c6865406d65696572736572766963652e6f6666696365'
(1) perl:   $RAD_REQUEST{'Message-Authenticator'} = &request:Message-Authenticator -> '0x916c9e5c3756daa1a354927ecec083df'
(1) perl:   $RAD_CHECK{'Auth-Type'} = &control:Auth-Type -> 'Perl'
(1) perl:   $RAD_CONFIG{'Auth-Type'} = &control:Auth-Type -> 'Perl'
rlm_perl: Config File /etc/privacyidea/rlm_perl.ini found!
rlm_perl: Debugging config: true
rlm_perl: Default URL 
rlm_perl: Looking for config for auth-type Perl
rlm_perl: RAD_REQUEST: User-Name = flhe@domain.internal
rlm_perl: RAD_REQUEST: Service-Type = Login-User
rlm_perl: RAD_REQUEST: Message-Authenticator = 0x916c9e5c3756daa1a354927ecec083df
rlm_perl: RAD_REQUEST: EAP-Message = 0x02a1001d01666c6865406d65696572736572766963652e6f6666696365
rlm_perl: RAD_REQUEST: Calling-Station-Id =
rlm_perl: RAD_REQUEST: NAS-IP-Address =
rlm_perl: Setting client IP to
rlm_perl: Auth-Type: Perl
rlm_perl: url:
rlm_perl: user sent to privacyidea: flhe@domain.internal
rlm_perl: realm sent to privacyidea: domain.internal
rlm_perl: resolver sent to privacyidea: 
rlm_perl: client sent to privacyidea:
rlm_perl: state sent to privacyidea: 
rlm_perl: urlparam user = flhe@domain.internal 
rlm_perl: urlparam client = 
rlm_perl: urlparam realm = domain.internal 
rlm_perl: urlparam pass =  
rlm_perl: Request timeout: 10 
rlm_perl: Not verifying SSL certificate!
rlm_perl: elapsed time for privacyidea call: 1.661939
rlm_perl: Content {"detail": {"message": "wrong otp pin", "threadid": 140248420035360}, "id": 1, "jsonrpc": "2.0", "result": {"status": true, "value": false}, "time": 1614695626.3164053, "version": "privacyIDEA 3.4.1", "versionnumber": "3.4.1", "signature": "rsa_sha256_pss:90c6f812e55d6bb03e41078467095e43bf8c6318475fd89ed21b54332595714c8ebc6f81b59fff878ef683e62e334402a8e775ce9b344a6a064d366e790c052b01f537005d8c2705c097b9d86c6812c2df982ba444d9821a4627ee67d956ed9eba756b98310a9156c659211ec05e3d35771e5796d5bb2e198fdb5f7c7e31ec9a3310c2171804e9b7c4edcd5e3d6e93100dcec4443c412b633839083a43ac2b1bdfa2464df254f28d22c3df3718f03722ed221e699b773b3633feff0369fffd506bd7747e62cc91f277214a7be9bcc64e5e5986ccc6e6549748c7974eb2052e0adde59aa93e2e61e127473176c52ebfb4a2657eba70a6fd7ab5ac4cf7f0426950"}
rlm_perl: privacyIDEA Result status is true!
rlm_perl: privacyIDEA access denied
rlm_perl: return RLM_MODULE_REJECT
(1) perl: &request:User-Name = $RAD_REQUEST{'User-Name'} -> 'flhe@domain.internal'
(1) perl: &request:Service-Type = $RAD_REQUEST{'Service-Type'} -> 'Login-User'
(1) perl: &request:Message-Authenticator = $RAD_REQUEST{'Message-Authenticator'} -> '0x916c9e5c3756daa1a354927ecec083df'
(1) perl: &request:EAP-Message = $RAD_REQUEST{'EAP-Message'} -> '0x02a1001d01666c6865406d65696572736572766963652e6f6666696365'
(1) perl: &request:Calling-Station-Id = $RAD_REQUEST{'Calling-Station-Id'} -> ''
(1) perl: &request:NAS-IP-Address = $RAD_REQUEST{'NAS-IP-Address'} -> ''
(1) perl: &reply:Reply-Message = $RAD_REPLY{'Reply-Message'} -> 'wrong otp pin'
(1) perl: &control:Auth-Type = $RAD_CHECK{'Auth-Type'} -> 'Perl'
(1)     [perl] = reject
(1)   } # Auth-Type Perl = reject
(1) Failed to authenticate the user
(1) Using Post-Auth-Type Reject
(1) Post-Auth-Type sub-section not found.  Ignoring.
(1) Delaying response for 1.000000 seconds
Waking up in 0.9 seconds.
(1) Sending delayed response
(1) Sent Access-Reject Id 40 from to length 35
(1)   Reply-Message = "wrong otp pin"
Waking up in 3.9 seconds.
(1) Cleaning up request packet ID 40 with timestamp +282
Ready to process requests

Given that I see a plain password when using radclient, which is absent in this case, I guess I’m missing the step of extracting somehow the password from the EAP message for the subsequent request to privacyIDEA.

Could you please tell me whether my scenario can be realised or - even better - give me a hint, which part I’m missing.

Thank you very much in advance.

Best regards,


Hi and welcome,

where do you see a password? I can not see any.
To my knowledge EAP would only support challenge response (CHAP / MSCHAPv2) with passwords.
privacyIDEA does not support one time passwords via challenge response.

Hi cornelinux,

thanks a lot for your really quick answer.

No, the password was only visible using radclient, which obviously doesn’t use EAP.

The following authentication methods for the remote identity would be at my disposal:

RSA signature:
Use of digital certificates with private RSA key and RSA signature scheme

Elliptic Curve Digital Signature Algorithm (ECDSA) with SHA-256 on the P-256 curve

ECDSA with SHA-384 on the P-384 curve

ECDSA with SHA-512 on the P-521 curve

Digital signature:
Use of configurable authentication methods with digital certificates as per RFC 7427. This procedure is an extensible and flexible authentication technique that allows padding and hash algorithms to be configured freely.

EAP can be used for any desired authentication method, e.g. TLS (authentication via certificate) or MSCHAP (authentication via user credentials).

Do you see any, which would work with privacyIDEA for my scenario?

Thanks a lot in advance

Best regards,


For authentication via (one-time-)passwords privacyIDEA supports PAP.
For supporting MSCHAPv2 we would have to greatly change the FreeRADIUS plugin and also do enhancements in the backend. The password is not transferred but only used to derive the response.
The server does not know, which one-time-password was used by the user.
This probably could be done, but we do not have it on the roadmap… …like never.

All (or probably most) digitial signature things or auth via client certificates can be done with FreeRADIUS. But as certificate authentication works you do not need the privacyIDEA server during authenitcation. However, you could use privacyIDEA to generate user certificates and the user could then use these for RADIUS authentication. (Without connecting FreeRADIUS to privacyIDEA!)

Dear cornelinux,

I do want to apologise again for my being in the process to understand what I have to do in order to make my scenario work. And I want to thank you for your inspiring help!

As I understood now with your help I have two possibilities:

  1. Plain unencrypted password from Radius client through EAP-*-PAP
  2. Generation of respective hash (e.g. MSCHAPv2) in the backend.

Ad 1.) It seems that EAP-TTLS-PAP is the only EAP protocol, which would be able to supply a clear text password. Anyway I very much doubt that the manufacturer of my routers will support it, if it is not currently supported.

Ad 2.) This is actually the method I would prefer given that it would largely increase the possibilities of privacyIDEA. It would involve passing the respective hash from radius to privacyIDEA and to generate the hash in the backend.

Would you please be so kind to explain to me whether in the privacyIDEA backend the possible OTPs for a single token are deterministic and whether the number is small enough to generate the hash for all of them in order to compare them to the hash provided by the FreeRadius plugin? (How many OTPs are there for one single token at one single moment in time?).

Thanks again for your help. It is very much appreciated!

Best regards,


It is not about the number of possible OTP values. It is usually rather small like 10.
Depending on the window that is defined. This is described in RFC 4226 and 6238.
With HOTP you can have blank presses, this is why the server must also check not only the current OTP values but also a defined number of further OTP values.
With TOTP you can have a clock drift. This is why the server must not only check the current OTP value but also some OTP values before and after the current time.

So it is not a matter of mere crunching power, but it is a matter of

  1. having the code in the freeradius plugin
  2. having the right privacyIDEA API do authenticate in this way
  3. having the code in the privacyIDEA server.

All three do not exist.

Dear cornelinux,

thank you very much for all your effort.

What would you say if I offered to do the implementation according to your specification?

Thanks a lot in advance.

Best regards,


I would say that the specification would probably take 2 days to investigate/define/write.

This is how we are doing privacyIDEA. The heavy lifting is not the actual coding. Actually privacyIDEA has very little lines of code. The heavy lifting is the finding out, what and how you want to do.
So providing a complete conecpt would be a big effort.

Could I support you in this process?

Thank you for asking. No, probably not. And honestly I (we) do not have the time.

Then I will try to continue on my own. So if you’re willing to share a couple of thoughts, I would appreciate it very much.

The following roughly needs to be done:

  1. find and and link the detailed specification for mschapv2.
  2. check, if it can be added in rlm_perl at all.
    So if mschapv2 is configure, we should see “something” in the authenticate method of the rlm_perl module.
  3. in respect to 1. we now need to clarify, what needs to be sent to privacyIDEA. A challenge, the message-authenticator…? Specify a list or parameters and how they need to be handled.
  4. We probably need to process several OTP values on the privacyIDEA server side. Depending on 3. this most probably can not be done with the exiting endpoints. So we need to define a new endpoint.
  5. Now we need to implement the endpoint,
  • library level
  • API level
  • unit tests
  1. Now we need to adapt our rlm_perl privacyIDEA script, so that it will - depending on the RADIUS request - either query the old /validate/check endpoint or the new endpoint.

Thanks a lot mate! I’ll keep you updated about the progress I make …