Using EAP and certificates

Sep 8, 2010 at 5:09 PM

Hi,

We are trying to use DotRas to create a VPN connection to a network that requires EAP and certificates.

On a non-programmatic way we would first install the certificate on the machine and then create the VPN connection using the "Automatic" VPN type, "Require encryption (disconnect if server declines)", EAP with "Microsoft Smart Card or other certificate" and select "Use a certificate on this computer" option.

How could we do the same using the DotRas library? Thoughts?

 

Thanks,

Robson

Coordinator
Sep 8, 2010 at 5:35 PM
Edited Sep 8, 2010 at 5:37 PM

The easiest way to programmatically generate an entry you would normally create manually would be to first create the connection manually, open the phonebook where the connection exists, and look at the RasEntry instance for that entry. If you copy down all of the properties on the object, and then set them in code, the entry should look and function exactly as your manual connection would.

Doing this will allow you to test your manual connection to ensure it works correctly prior to duplicating those settings in code. That way if any problems do occur from the programmatic entry, they're easier to isolate during development.

using DotRas;

RasPhoneBook pbk = new RasPhoneBook();
pbk.Open();

RasEntry entry = pbk.Entries["Your Connection"];
// You can now look at the properties on entry to see what settings you need to use.

Edit: Added the example code.

Sep 8, 2010 at 6:10 PM

Dear Jeff,

 

Thanks for your prompt response.

 

 

I already did what you told me (by opening the Windows phone book and copying the information into the phonebook I am using) and the DotRas library can correctly pull up the information but the dialing process does not work.

 

By researching the internet it seems that I have to call a function called RasGetEapUserIdentity or RasGetEapInfo prior to dialing. When the information is received from those functions I should pass that into the RasDialer.

I could not find - so far - a piece of code for the P/Invoke signatures of such functions.

 

Any ideas?

 

Thanks,

Robson

 

Coordinator
Sep 8, 2010 at 7:57 PM
Edited Sep 8, 2010 at 7:59 PM

The RasGetEapUserIdentity and RasFreeEapUserIdentity APIs are already fully integrated into the project. There is an EapData property on the RasDialer class that's supposed to take EAP data and then pass that into the dialer, but it looks like that might get overridden during dialing if an entry name has been provided. By the looks of it, I need to remove that property off the object unless I expose the RasGetEapUserData API on the RasEntry class, which sounds like a good feature request for 1.3. You can also try using the UpdateCredentials method on RasEntry in the WINXP or later build type to store the client certificate.

I'm not that familar with EAP, so testing those functions is a bit of a problem for me. However, what I can do is fix the bug with RasDialer so the data from the component will be passed into the call to RasDial. All you will need to do then is implement the RasGetEapUserData and RasSetEapUserData methods. Extension methods would work well for this situation (if you're using .NET 3.0 or later), you just need to add it to the RasEntry class.

public static class Extensions
{
    public RasEapInfo GetEapUserData(this RasEntry entry)
    {
        // Add your implementation for RasGetEapUserData here.
    }

    public void SetEapUserData(this RasEntry entry, RasEapInfo eapData)
    {
        // Add your implementation for RasSetEapUserData here.
    }
}

This should give you access to all the RasEntry members until I can do the implementation for those APIs. I don't want to put it into this build since it's already in the release stage and considered feature complete, but I can definitely get it into 1.3.

Here's the links to the two functions in RAS:

RasGetEapUserData: http://msdn.microsoft.com/en-us/library/aa377521(v=VS.85).aspx

RasSetEapUserData: http://msdn.microsoft.com/en-us/library/aa377817(v=VS.85).aspx

Edit: If you get RasSetEapUserData working, you may not need to implement the call for RasGetEapUserData. It may just flow naturally through the RasDialer since RasGetEapUserIdentity is already implemented once you set the data for the entry.

Sep 9, 2010 at 4:50 PM

Jeff,

Would you mind sending me the P/Invoke signatures for these two functions?

I will test it and let you know how it works.

Once the procedure works on my end, I will be more than glad to share with you and the community.

Thank you,

Robson

From: jeff_winn [mailto:notifications@codeplex.com]
Sent: Wednesday, September 08, 2010 4:57 PM
To: msdn@vivee.com.br
Subject: Re: Using EAP and certificates [DotRas:226491]

From: jeff_winn

The RasGetEapUserIdentity and RasFreeEapUserIdentity APIs are already fully integrated into the project. There is an EapData property on the RasDialer class that's supposed to take EAP data and then pass that into the dialer, but it looks like that might get overridden during dialing if an entry name has been provided. By the looks of it, I need to remove that property off the object unless I expose the RasGetEapUserData API on the RasEntry class, which sounds like a good feature request for 1.3. You can also try using the UpdateCredentials method on RasEntry in the WINXP or later build type to store the client certificate.

I'm not that familar with EAP, so testing those functions is a bit of a problem for me. However, what I can do is fix the bug with RasDialer so the data from the component will be passed into the call to RasDial. All you will need to do then is implement the RasGetEapUserData and RasSetEapUserData methods. Extension methods would work well for this situation (if you're using .NET 3.0 or later), you just need to add it to the RasEntry class.

public static class Extensions
{
    public RasEapInfo GetEapUserData(this RasEntry entry)
    {
        // Add your implementation for RasGetEapUserData here.
    }
 
    public void SetEapUserData(this RasEntry entry, RasEapInfo eapData)
    {
        // Add your implementation for RasSetEapUserData here.
    }
}

This should give you access to all the RasEntry members until I can do the implementation for those APIs. I don't want to put it into this build since it's already in the release stage and considered feature complete, but I can definitely get it into 1.3.

Here's the links to the two functions in RAS:

RasGetEapUserData: http://msdn.microsoft.com/en-us/library/aa377521(v=VS.85).aspx

RasSetEapUserData: http://msdn.microsoft.com/en-us/library/aa377817(v=VS.85).aspx

Read the full discussion online.

To add a post to this discussion, reply to this email (DotRas@discussions.codeplex.com)

To start a new discussion for this project, email DotRas@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on CodePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at CodePlex.com

Coordinator
Sep 9, 2010 at 5:35 PM
Edited Nov 6, 2010 at 3:38 AM

Any code I place below will be completely untested, so it may not work at all.

using System;
using System.Runtime.InteropServices;

[DllImport("rasapi32.dll", CharSet = CharSet.Unicode)]
public static extern int RasSetEapUserData(
    IntPtr handle,
    string pszPhonebook,
    string pszEntry,
    IntPtr pbEapData,
    int dwSizeOfEapData);

[DllImport("rasapi32.dll", CharSet = CharSet.Unicode)]
public static extern int RasGetEapUserData(
    IntPtr handle,
    string pszPhonebook,
    string pszEntry,
    out IntPtr pbEapData,
    ref IntPtr pdwSizeOfEapData);

If you use RasGetEapUserData you're going to need to call the function twice. Once with a pdwSizeOfEapData value of IntPtr.Zero, check for the ERROR_BUFFER_TOO_SMALL result, and then use Marshal.AllocHGlobal to allocate the correct amount of space identified by pdwSizeOfEapData for the pbEapData pointer. A good example in the project would be the RasHelper.GetActiveConnections method, I've done something similar in there. For both methods and simplicity of the API for now, you might want to just pass IntPtr.Zero for the handle on both API calls to use the current user context.

Edit: Had to fix the DllImport attribute, the assembly name was wrong.

Sep 9, 2010 at 6:26 PM

Jeff,

What about the RasGetEapUserIdentity and RasFreeEapUserIdentity?

Do I need those?

Thanks,

From: jeff_winn [mailto:notifications@codeplex.com]
Sent: Thursday, September 09, 2010 2:36 PM
To: msdn@vivee.com.br
Subject: Re: Using EAP and certificates [DotRas:226491]

From: jeff_winn

Any code I place below will be completely untested, so it may not work at all.

using System;
using System.Runtime.InteropServices;
 
[DllImport("rasdial32.dll", CharSet = CharSet.Unicode)]
public static extern int RasSetEapUserData(
    IntPtr handle,
    string pszPhonebook,
    string pszEntry,
    IntPtr pbEapData,
    int dwSizeOfEapData);
 
[DllImport("rasdial32.dll", CharSet = CharSet.Unicode)]
public static extern int RasGetEapUserData(
    IntPtr handle,
    string pszPhonebook,
    string pszEntry,
    out IntPtr pbEapData,
    ref IntPtr pdwSizeOfEapData);

If you use RasGetEapUserData you're going to need to call the function twice. Once with a pdwSizeOfEapData value of IntPtr.Zero, check for the ERROR_BUFFER_TOO_SMALL result, and then use Marshal.AllocHGlobal to allocate the correct amount of space identified by pdwSizeOfEapData for the pbEapData pointer. A good example in the project would be the RasHelper.GetActiveConnections method, I've done something similar in there. For both methods and simplicity of the API for now, you might want to just pass IntPtr.Zero for the handle on both API calls to use the current user context.

Read the full discussion online.

To add a post to this discussion, reply to this email (DotRas@discussions.codeplex.com)

To start a new discussion for this project, email DotRas@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on CodePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at CodePlex.com

Coordinator
Sep 9, 2010 at 6:40 PM

You shouldn't need them, those are already being handled for you inside the assembly. However, keep in mind I haven't done this before so you might need them (but I doubt it). If you do, just look at the DotRas.Internal.RasHelper.Dial method... you'll be able to trace how they're being used and where the definitions are from there. They will be in either the SafeNativeMethods or UnsafeNativeMethods class, both of which are in the DotRas.Internal namespace. That section is designed to be mocked, so tracing the code might be a bit difficult.

Once dialing is initiated by the RasDialer class, it automatically calls the RasGetEapUserIdentity API for you to determine whether the connection uses EAP. That's why I said you may only need to implement the RasSetEapUserData API since you shouldn't need to pass the EAP data into the dialer manually, hopefully the rest of the existing code will take over and it'll just work.

Coordinator
Sep 9, 2010 at 6:45 PM

I am curious what you plan to put inside the memory address specified for the pbEapData argument on RasSetEapUserData. I'm not familiar with EAP, how do you know what's supposed to be put in the memory address?

I'd like to make that section more developer friendly if possible.

Dec 1, 2016 at 3:40 PM
Hi..just to revive the thread...any update on how to configure certificates (or eventually username/password) with EAP and DotRas ?
Dec 1, 2016 at 4:59 PM
Edited Dec 1, 2016 at 5:00 PM
Just an update, managed to get it working. When using EAP you have to set a particular value in the field VpnEntry.CustomAuthKey which specifies which EAP authentication method to use. For EAP-MSCHAPV2 you can set credentials with usual VpnEntry.UpdateCredentials. To setup your certificates you have to use value 13, here follows the table I managed to extract.

// 23 EAP-AKA
// 50 EAP-AKA'
// 18 EAP-SIM
// 21 EAP-TTLS
// 25 PEAP
// 26 EAP-MSCHAPV2
// 13 EAP-smart card or certificate

VpnEntry.Options.RequireEap = true;
VpnEntry.CustomAuthKey=26; // 26 means eap-mschapv2 username/password
VpnEntry.UpdateCredentials(new System.Net.NetworkCredential(user,password));

You still have to figure how to specify the certificate, but I think this could be useful.
Coordinator
Feb 4 at 11:50 AM
Glad you got some of it working, that was always one of the areas I wasn't sure how to setup since I don't have access to the different configurations for RAS like EAP and such (or at least not very easily).

Couple questions:
  1. Where did that table you extracted come from? Everytime I've tried to find something like that I wasn't able to determine what the correct set of values were.
  2. If you're able to document what else you'd need from the library to fully support it here, it'd help me out greatly trying to get the rest of the API plugged in.
Thanks for the information!