<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Windows CE Networking Team WebLog : Author: Jeff Kelley</title><link>http://blogs.msdn.com/cenet/archive/tags/Author_3A00_+Jeff+Kelley/default.aspx</link><description>Tags: Author: Jeff Kelley</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Creating MPPE Attributes in an EAP Extension</title><link>http://blogs.msdn.com/cenet/archive/2007/04/05/creating-mppe-attributes-in-an-eap-extension.aspx</link><pubDate>Thu, 05 Apr 2007 21:24:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2034418</guid><dc:creator>cenet</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/cenet/comments/2034418.aspx</comments><wfw:commentRss>http://blogs.msdn.com/cenet/commentrss.aspx?PostID=2034418</wfw:commentRss><description>&lt;P&gt;When an EAP extension succesfully completes authentication, it can fill in the PPP_EAP_OUTPUT pUserAttributes field with MPPE key information for use by other networking components. For example, RAS can use those keys for data encryption, and WPA/WPA2 will use them for the 4-way handshake on an 802.11 link.&lt;/P&gt;
&lt;P&gt;The PPP_EAP_OUTPUT pUserAttribute field points to an array of RAS_AUTH_ATTRIBUTE structures, terminated by an array element with raaType = raatMinimum. Documentation on the format of the RAS_AUTH_ATTRIBUTE structure can be found&amp;nbsp;at &lt;A href="http://msdn2.microsoft.com/en-gb/library/aa363535.aspx" mce_href="http://msdn2.microsoft.com/en-gb/library/aa363535.aspx"&gt;http://msdn2.microsoft.com/en-gb/library/aa363535.aspx&lt;/A&gt;.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;For MPPE Keys, there will be&amp;nbsp;2 elements in the array of RAS_AUTH_ATTRIBUTES: one for the send key and one for&amp;nbsp;the receive key. For the MPPE Key attributes, the PVOID Value field of the RAS_AUTH_ATTRIBUTE will point to a structure&amp;nbsp;that is described in&amp;nbsp;&lt;A href="http://msdn2.microsoft.com/en-us/library/aa363636.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/aa363636.aspx"&gt;http://msdn2.microsoft.com/en-us/library/aa363636.aspx&lt;/A&gt;. See the section labeled "eatVendorSpecific".&lt;/P&gt;
&lt;P&gt;Below are some sample utility functions that can assist in the creation of the data structures that contain these keys.&lt;/P&gt;&lt;PRE&gt;struct RAS_AUTH_ATTRIBUTE_VALUE
{
    BYTE VendorId[4];    // network byte order
    BYTE VendorType;
    BYTE Length;         // number of bytes from VendorType to the end of the value
    BYTE VendorValue[1]; // Length-2 bytes long
};
      
DWORD
MyEapUtilAuthAttributeInsertVSA(
    OUT RAS_AUTH_ATTRIBUTE *    pAttribute,
    IN  DWORD                   VendorId,
    IN  BYTE                    VendorType,
    IN  PBYTE                   pVendorValue,
    IN  BYTE                    cbVendorValue)
//
//    Insert a vendor specific attribute into the location pointed to by pAttribute.
//
{
      DWORD  dwResult = NO_ERROR;

      ASSERT(cbVendorValue &amp;lt; 254);

      pAttribute-&amp;gt;raaType = raatVendorSpecific;
      pAttribute-&amp;gt;dwLength = offsetof(struct RAS_AUTH_ATTRIBUTE_VALUE, VendorValue) + cbVendorValue;
      pAttribute-&amp;gt;Value = LocalAlloc(LPTR, pAttribute-&amp;gt;dwLength);
      if (pAttribute-&amp;gt;Value == NULL)
      {
            dwResult = ERROR_OUTOFMEMORY;
      }
      else
      {
            struct RAS_AUTH_ATTRIBUTE_VALUE *pAttributeValue = (struct RAS_AUTH_ATTRIBUTE_VALUE *)pAttribute-&amp;gt;Value;

            VendorId = htonl(VendorId);
            memcpy(&amp;amp;pAttributeValue-&amp;gt;VendorId[0], &amp;amp;VendorId, sizeof(VendorId));
            pAttributeValue-&amp;gt;VendorType = VendorType;
            pAttributeValue-&amp;gt;Length = 2 + cbVendorValue; // 1 byte for VendorType, 1 byte for Length, then cbVendorValue bytes of VendorValue
            memcpy(&amp;amp;pAttributeValue-&amp;gt;VendorValue[0], pVendorValue, cbVendorValue );
      }
      return dwResult;
}

RAS_AUTH_ATTRIBUTE *
MyEapUtilAuthAttributeArrayAlloc(
      DWORD nAttrs)
//
//  Allocate an array of sufficient size to hold the requested number
//  of authentication attributes.
//
{
      RAS_AUTH_ATTRIBUTE *pAttributes;

      nAttrs += 1; // Add one for the terminator
      pAttributes = (RAS_AUTH_ATTRIBUTE *)(LocalAlloc(LPTR, nAttrs * sizeof(RAS_AUTH_ATTRIBUTE)));
      if (pAttributes)
      {
            // Set the terminator array element
            pAttributes[nAttrs - 1].raaType = raatMinimum;
      }
      return pAttributes;
}

void
MyEapUtilAuthAttributeArrayFree(
      RAS_AUTH_ATTRIBUTE *pAttributes)
//
//  Free an array of authentication attribute values.
//
{
    if (pAttributes)
    {
        for (int i=0; pAttributes[i].raaType != raatMinimum; i++)
        {
            if (pAttributes[i].Value)
            {
                SecureZeroMemory(pAttributes[i].Value, pAttributes[i].dwLength);
                LocalFree(pAttributes[i].Value);
                pAttributes[i].Value = NULL;
            }
        }
        LocalFree(pAttributes);
    }
}

#define VENDOR_MICROSOFT     311
#define MS_VSA_MPPE_Send_Key 16
#define MS_VSA_MPPE_Recv_Key 17

#define MAX_MPPEKEY_LENGTH   32

// Format of the MPPE Key
// Byte 1-2:       Salt
// Byte 3:         Key Length (this is the length of the Actual Key and does not include Salt, Key Length and Padding fields) 
// Byte 4-35:      Actual Key  (Most access points require 32 byte keys for WPA)
// Byte 35-50:     Padding (required to make the length of the MPPE Key (not including the Salt) a multiple of 16 bytes)

struct MPPEKey
{
    BYTE Salt[2];
    BYTE KeyLength;
    BYTE Key[MAX_MPPEKEY_LENGTH];
    BYTE Padding[15];
};

DWORD
MyEapUtilAuthAttributeInsertMPPEKeyVSA(
    OUT RAS_AUTH_ATTRIBUTE *    pAttribute,
    IN  BYTE                    VendorType, // MS_VSA_MPPE_Send_Key or MS_VSA_MPPE_Recv_Key
    IN  BYTE const * const      pKey,
    IN  size_t                  cbKey)
//
//  Insert an MPPEKey VSA into the location specified by pAttribute.
//
{
    DWORD  dwResult;
    struct MPPEKey MPPEKey;
 
    if (cbKey &amp;gt; MAX_MPPEKEY_LENGTH)
        return ERROR_INVALID_PARAMETER;

    memset(&amp;amp;MPPEKey, 0, sizeof(MPPEKey));
    MPPEKey.KeyLength = cbKey;
    memcpy(&amp;amp;MPPEKey.Key[0], pKey, cbKey);
    dwResult = MyEapUtilAuthAttributeInsertVSA(pAttribute, VENDOR_MICROSOFT, VendorType, (PBYTE)&amp;amp;MPPEKey, sizeof(MPPEKey) - MAX_MPPEKEY_LENGTH + cbKey);  
    SecureZeroMemory(&amp;amp;MPPEKey, sizeof(MPPEKey));
    return dwResult;
}
    
DWORD 
MyEapUtilCreateMPPEAuthAttributes(
    BYTE const * const pSendKey,
    size_t             cbSendKey,
    BYTE const * const pRecvKey,
    size_t             cbRecvKey,
    RAS_AUTH_ATTRIBUTE **ppSendRecvKeyAttr)
//
// Save the MPPE Send and Recv Session Keys as Auth Attributes
//
{
    DWORD dwResult;
    RAS_AUTH_ATTRIBUTE* pSendRecvKeyAttr;

    // Allocate an auth attribute array able to hold 2 attributes (send key and recv key)
    pSendRecvKeyAttr = MyEapUtilAuthAttributeArrayAlloc(2); 
    if ( NULL == pSendRecvKeyAttr )
    {
        dwResult = ERROR_OUTOFMEMORY;
        goto done;
    }

    // Add the send key to the attribute array at index 0
    dwResult = MyEapUtilAuthAttributeInsertMPPEKeyVSA(&amp;amp;pSendRecvKeyAttr[0], MS_VSA_MPPE_Send_Key, pSendKey, cbSendKey);
    if (dwResult != NO_ERROR)
          goto done;

    // Add the receive key to the attribute array at index 1
    dwResult = MyEapUtilAuthAttributeInsertMPPEKeyVSA(&amp;amp;pSendRecvKeyAttr[1], MS_VSA_MPPE_Recv_Key, pRecvKey, cbRecvKey);
    if (dwResult != NO_ERROR)
          goto done;
          
done:
    if (dwResult != NO_ERROR)
    {
        // Free any resources
        MyEapUtilAuthAttributeArrayFree(pSendRecvKeyAttr);
        pSendRecvKeyAttr = NULL;
    }

    *ppSendRecvKeyAttr = pSendRecvKeyAttr;
    return dwResult;
}

&lt;/PRE&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=2034418" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/cenet/archive/tags/Author_3A00_+Jeff+Kelley/default.aspx">Author: Jeff Kelley</category></item><item><title>Wifi driver handling of OID_802_11_SSID set requests</title><link>http://blogs.msdn.com/cenet/archive/2006/10/23/wifi-driver-handling-of-oid-802-11-ssid-set-requests.aspx</link><pubDate>Mon, 23 Oct 2006 22:27:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:865134</guid><dc:creator>cenet</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/cenet/comments/865134.aspx</comments><wfw:commentRss>http://blogs.msdn.com/cenet/commentrss.aspx?PostID=865134</wfw:commentRss><description>&lt;P&gt;Wireless Zero Configuration (WZC) will issue OID_802_11_SSID set requests to an 802.11 (Wifi) miniport driver in a couple of distinct circumstances:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;WZC wants the miniport&amp;nbsp;adapter to associate with Access Points (APs) that match the specified SSID, or&lt;/LI&gt;
&lt;LI&gt;WZC wants the miniport adapter to&amp;nbsp;disassociate from any/all APs&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;In case #2, WZC attempts to cause the disassociation by generating a random SSID that is 32 bytes long, with each byte of the SSID in the range 0x01 - 0x1F. WZC expects that the adapter will be unable to find an AP with SSID that matches the randomly generated one and thus the adapter will end up disassociated.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;It is inefficient in both time and power consumption, however, to attempt to connect to that SSID when what is desired is disassociation. Thus it would be preferable if a miniport driver detects this "special" SSID value that WZC issues in a set request and immediately disassociates rather than attempt to associate to it.&lt;/P&gt;
&lt;P&gt;Sample code that would identify this special SSID would be something like:&lt;/P&gt;&lt;PRE&gt;    boolean
    SSIDIsValid(
	    const NDIS_802_11_SSID *pSSID)
    //
    //  WZC will set the SSID to a random string of 32 invalid
    //  characters in the range 0x01 - 0x1F in order to stop
    //  an adapter from associating with any SSID.
    //
    //  Return false if the SSID is one of these special values
    //  being set by WZC.
    {
	    boolean isValid = true;
	    UINT    i;

	    if (pSSID-&amp;gt;SsidLength == 32)
	    {
		    isValid = false;
		    for (i = 0; i &amp;lt; 32; i++)
			    if (!(0 &amp;lt; pSSID-&amp;gt;Ssid[i] &amp;amp;&amp;amp; pSSID-&amp;gt;Ssid[i] &amp;lt;= 0x1F))
			    {
				    isValid = true;
				    break;
			    }
	    }
	    return isValid;
    }

    NDIS_STATUS
    MyMiniportSSIDSetRequestHandler(
	    IN NDIS_802_11_SSID *SSID)
    //
    //  Function that handles OID_802_11_SSID Set Requests
    //
    {
        boolean WantToBeConnected = SSIDIsValid(SSID);
        if (false == WantToBeConnected)
        {
            // WZC is requesting that we disassociate
            // [Insert code that disassociates]
        }
        else
        {
            // WZC is requesting that we associate with the specified SSID
            // [Insert code that handles association]
        }

    }
&lt;/PRE&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=865134" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/cenet/archive/tags/Author_3A00_+Jeff+Kelley/default.aspx">Author: Jeff Kelley</category></item></channel></rss>