Windows CE Networking Team WebLog

Windows CE Networking - from NDIS to TCP to SOAP to VOIP and everything in between.

Creating MPPE Attributes in an EAP Extension

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.

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 at http://msdn2.microsoft.com/en-gb/library/aa363535.aspx

For MPPE Keys, there will be 2 elements in the array of RAS_AUTH_ATTRIBUTES: one for the send key and one for the receive key. For the MPPE Key attributes, the PVOID Value field of the RAS_AUTH_ATTRIBUTE will point to a structure that is described in http://msdn2.microsoft.com/en-us/library/aa363636.aspx. See the section labeled "eatVendorSpecific".

Below are some sample utility functions that can assist in the creation of the data structures that contain these keys.

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 < 254);

      pAttribute->raaType = raatVendorSpecific;
      pAttribute->dwLength = offsetof(struct RAS_AUTH_ATTRIBUTE_VALUE, VendorValue) + cbVendorValue;
      pAttribute->Value = LocalAlloc(LPTR, pAttribute->dwLength);
      if (pAttribute->Value == NULL)
      {
            dwResult = ERROR_OUTOFMEMORY;
      }
      else
      {
            struct RAS_AUTH_ATTRIBUTE_VALUE *pAttributeValue = (struct RAS_AUTH_ATTRIBUTE_VALUE *)pAttribute->Value;

            VendorId = htonl(VendorId);
            memcpy(&pAttributeValue->VendorId[0], &VendorId, sizeof(VendorId));
            pAttributeValue->VendorType = VendorType;
            pAttributeValue->Length = 2 + cbVendorValue; // 1 byte for VendorType, 1 byte for Length, then cbVendorValue bytes of VendorValue
            memcpy(&pAttributeValue->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 > MAX_MPPEKEY_LENGTH)
        return ERROR_INVALID_PARAMETER;

    memset(&MPPEKey, 0, sizeof(MPPEKey));
    MPPEKey.KeyLength = cbKey;
    memcpy(&MPPEKey.Key[0], pKey, cbKey);
    dwResult = MyEapUtilAuthAttributeInsertVSA(pAttribute, VENDOR_MICROSOFT, VendorType, (PBYTE)&MPPEKey, sizeof(MPPEKey) - MAX_MPPEKEY_LENGTH + cbKey);  
    SecureZeroMemory(&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(&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(&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;
}

Published Thursday, April 05, 2007 11:24 AM by cenet
Filed under:

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

No Comments

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: Required
Submit

© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker