Welcome to MSDN Blogs Sign in | Join | Help

Just encountered this while attempting to call an 'https' web service that required NTLM authentication.

Exception text:

"The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'Negotiate,NTLM'."

Solution:

Changed clientCredentialType to 'windows'. Do this in the app.config.

Changed from:

<security mode="Transport">
    <transport clientCredentialType="None" proxyCredentialType="None"
        realm="" />
    <message clientCredentialType="UserName" algorithmSuite="Default" />
</security>

To:

<security mode="Transport">
    <transport clientCredentialType="Windows" />
</security>

Do not change security mode to 'TransportCredentialOnly' the service is 'https'. That threw me, I saw that solution on several sites but they were addressing 'https' services, just NTLM.

Resources:
This post helped me to work out what was going on:
http://geekswithblogs.net/socasanta/archive/2007/07/06/113725.aspx

I just came across this whilst making a web service call from a Windows Forms client application.

Exception text:

"The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:GetWizardInfoResponse. The InnerException message was 'There was an error deserializing the object of type DataManagementConsoleFileProducer.RegSysWebService.GetWizardInfoResponseBody. The maximum string content length quota (8192) has been exceeded while reading XML data. This quota may be increased by changing the MaxStringContentLength property on the XmlDictionaryReaderQuotas object used when creating the XML reader. Line 222, position 14.'.  Please see InnerException for more details."

Solution:

Increase maxStringContentLength value in the readerQuotas element in projects app.config file.

<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
    maxBytesPerRead="4096" maxNameTableCharCount="16384" />

Resources:
This post helped me to work out what was going on:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3077193&SiteID=1

Whilst building an 'custom action' to install a database, I encountered a SqlException ("Incorrect syntax near...") when calling ExecuteNonQuery(). To solve the problem process sql commands separately (using 'GO' as a delimiter). Thankfully parsing the ".sql" file into commands is fairly straight forward:

 

    string[] commands = sql.Split( 
        new string[]{"GO\r\n", "GO ", "GO\t"}, StringSplitOptions.RemoveEmptyEntries );
    foreach (string c in commands)
    {
        command = new SqlCommand(c, masterConnection);
        command.ExecuteNonQuery();
    }
    }
    catch (Exception e)
    {
        MessageBox.Show(e.Message);
    }
    finally
    {
        masterConnection.Close();
    }
}

Dan Griffin
JWSecure, Inc.

May 2007

Applies to:
 Windows Vista

Summary: This whitepaper and accompanying sample demonstrates how to create and us a plug-in to support a new cipher algorithm in Windows; specifically TwoFish.  Using a plug-is ideal, as existing crypto-agnostic applications can continue to use the existing messaging and encryption APIs without modification (15 printed pages). Download XPS version.

Download the associated sample code, CNGSample.exe.

Dependencies
You must have the CNG SDK and the Windows SDK for Windows Vista. If you do not install these components to the default locations, which are listed below, you must update the Visual Studio Include and Library paths in the sample code accordingly.

Download the CNG SDK
The CNG SDK installs to %ProgramFiles%\Microsoft CNG Development Kit.

Download the Windows SDK for Windows Vista
The Windows Vista SDK installs to %ProgramFiles%\Microsoft SDKs\Windows\v6.0.

Introduction

This is the first in a series of articles about some of the new security-related features in Windows Vista.  My goal is highlight these areas for the Windows developer community.  However, I’ll only be talking about stuff that I think is cool!

This article is written for any developer familiar with programming on Windows.  Most of the topics I’m addressing relate to new functionality in Windows Vista that’s only available with native APIs (as opposed to with the Microsoft .NET Framework) as of the time of this writing.  However, whenever I can tie into the managed code side of things, I will.

In summary, if you’ve previously done some Windows programming with C, C++, and/or C#, you’ll find this series to be accessible and hopefully interesting as well.

Summary of Topics in This Series

As a teaser for what’s coming, here are the topics that I plan on covering in this series.  Of course, until all is said and done, this list is subject to change:

· CNG (Crypto API: Next Generation)

· Windows Filtering Platform API

· IPsec (including AuthIP)

· Smart Card Module (“mini-driver”) plug-in interface

· IPv6

· Fuzz Testing

As I mentioned above, these are topics that really interest me right now – I think they’re cool. But more than that, these topics represent areas of significant investment and demand in the computer industry right now--namely, data encryption, network security, strong authentication, and software security testing.  Therefore, I consider it important to be as informed about them as possible.

So, let’s proceed to the first topic – Crypto API: Next Generation

Crypto API: Next Generation

Crypto API: Next Generation (CNG) is a new suite of Win32/native cryptography-related interfaces present in Windows Vista. CNG offers a number of attractive features for application developers:

· Crypto Isolation – Long-term private key material can now be hosted in a secure system process.

· Better Extensibility – For example, a custom random number generator can now be installed, as well as multiple distinct implementations of a given cryptographic algorithm.

· Ease of Plug-in Creation – Developers need no longer implement a complex plug-in just to add a new symmetric encryption or cryptographic hash algorithm to Windows.

· “Crypto Agnostic” Support – CNG allows crypto-aware applications, including APIs built on top of cryptographic primitives, to not be bound to specific algorithms, signature schemes, or key agreement protocols.

Each of the above was difficult to accomplish by using the previous version of Crypto API.

That said, my goal in this article is not to promote the high-level benefits of the new API, but rather to buckle down and show it in action. My example focuses on the second two points above: the creation of a crypto plug-in and its smooth incorporation into the application stack. To motivate this discussion, I want to first consider a sample business problem facing a software company that produces an application with cryptographic messaging capabilities.

Sample Business Problem

In this example, imagine that I’m the lead architect at a software vendor. The company I work for, we’ll call it Contoso, is working on a standards-based application that uses the Windows Cryptographic Message Syntax (CMS) APIs. An example application would be an S/MIME-capable e-mail client like Outlook. A large, important customer of ours has been demanding that we provide support in the application for a new symmetric encryption algorithm. For this example, I’ve chosen Twofish, a block cipher that was one of the contenders a few years back for the Advanced Encryption Standard (AES) competition. This type of customer need might be compliance-driven, or even based on government-originated national security requirements. Regardless, if we want to keep their business, we had better get to work!

In summary, my goal is to use a plug-in to support a new cipher algorithm in Windows; specifically TwoFish in this example.  Using a plug-in would be ideal, so that the application can continue to use the existing messaging and encryption APIs. In fact, my secondary goal is to completely avoid changing my application code.  That said if “crypto-agnostic” wasn’t an original requirement of the application architecture; some additional application code changes are likely to be necessary the first time around.  On the upside, once I’ve done those changes correctly, I won’t have to touch the application code at all the next time a customer requires such an extension.

Historically, adding a cipher algorithm to Windows used to be a painful thing to accomplish from an engineering standpoint.  Applications could generally be made to support new symmetric encryption algorithms in a pluggable way, but the scenario required implementing a plug-in known as a cryptographic service provider (CSP) for previous versions of Crypto API.  This was a huge undertaking, requiring support for a suite of asymmetric, hashing, and symmetric encryption functionality, not to mention enumeration and metadata-related interfaces for all of the above. To give a rough idea of the work required: implementing and testing a new CSP for the purpose of satisfying the customer requirement in this example could easily have taken six to twelve months of engineering cost for an experienced team! And that’s just for this one cipher algorithm.

In Windows Vista, by using CNG, writing a cipher plug-in is relatively trivial. However, the CNG plug-in alone is not sufficient to meet our customer’s needs. We must implement plug-in support for the new algorithm at the messaging layer as well. I’ll discuss both plug-in layers below.

Sample Solution

As discussed in the previous section, my customer wants support for the TwoFish symmetric cipher to be built-in to my PKI-based messaging application.  From an engineering perspective, this problem can be relatively easily solved in Windows Vista by implementing the following three interfaces:

· BCRYPT_CIPHER_FUNCTION_TABLE – This is the interface that allows me to enable Twofish as a symmetric cipher to any CNG-aware application (or system component, such as the Windows cryptographic messaging API; see the next two bullets).

· CMSG_OID_CNG_GEN_CONTENT_ENCRYPT_KEY_FUNC – This is the interface that allows me to enable Twofish as a content encryption algorithm in the context of the ASN.1 and X.509 standards-based messaging APIs. These use CNG.

· CMSG_OID_CNG_IMPORT_CONTENT_ENCRYPT_KEY_FUNC – This is the interface, closely related to “GEN_CONTENT” above, that allows me to recover the key material from a decrypted message.  I then return the Twofish key handle so the rest of the message can be decrypted.

Admittedly, as I am writing this, there are some important real-world considerations to take into account:

· My theoretical customer is unlikely to be satisfied with a solution that only works for Windows Vista. The customer’s minimum requirement could be support for Windows XP and Windows Server 2003, especially in the case of existing large deployments.

· Microsoft has announced that there are no plans to port CNG down-level.

· Microsoft has indicated that the previous version of Crypto API is likely to be removed in future versions of Windows.

As mentioned above, supporting earlier versions of Windows in this scenario is feasible; it’s just more work.  However, it should be noted that, if engineered properly, the Windows Vista portion of a down-level compatible solution is pretty much a strict subset of the overall effort, due to the common characteristics of pluggable crypto interfaces.

Solution Architecture

This section presents the architectural details of the solution and provides an architectural diagram, which you’ll find below.  The overall Windows crypto architecture has some interesting cross-dependencies, many of which are not depicted in the diagram.  However, note that my plug-in module implements interfaces at two different architectural layers.  The higher layer is so-called Crypto API 2.0 (CAPI2), where the certificate and message encoding logic lives.  This is where I plug-in the capability to generate and import a Twofish content encryption key.  But both capabilities – key generation and importation – are actually implemented at the CNG layer, which is where the other logical half where my plug-in is defined.  Therefore, twofish.dll is used at both architectural layers.

Why does CAPI2 require a special messaging plug-in to handle importing and generating a symmetric key when it could instead use the algorithm identifier to call directly into CNG with BCryptGenerateSymmetricKey?  The problem is that there are a variety of characteristics that define the use of a given cipher in the context of a given application.  These include key size, cipher mode, salt, initialization vector (IV), and others.  In addition, the proper wire encoding of parameters like the IV, which must be included with the message, must also be handled at this layer (as opposed to the low-level algorithmic layer – CNG).  Therefore, defining even the common encryption and encoding options without the use of a general callback scheme becomes burdensome.

The following diagram and bullets describe the logical plug-in points for the sample twofish.dll from the perspective of the test application that accompanies it.  In summary, the test application (TFTest.exe) creates a certificate and RSA key pair, encrypts a message with that certificate by using Twofish, and then decrypts the same message.

Figure 1 - Solution Architectural Diagram

The numbered steps below correspond to the numbers in the diagram:

1. The first step taken by the test is to create a persisted RSA key pair via CNG.  In general, persisted keys are handled with the NCrypt API layer.

2. Based on the RSA key pair, the test uses the X.509 digital certificate manipulation APIs in CAPI2 to create a temporary recipient certificate.  This certificate represents the party to whom I’m pretending to send an encrypted message.  Once the certificate is created, I call CryptEncryptMessage, specifying the recipient certificate as well as a custom cryptographic algorithm object identifier (also known as OID) representing Twofish.

3. The specified custom object identifier gets mapped to twofish.dll through the system registry, resulting in a call to my Twofish-specific implementation of the CMSG_OID_CNG_GEN_CONTENT_ENCRYPT_KEY_FUNC interface.

4. In order to create a Twofish content encryption key handle, I must call into CNG. Cryptographic primitives, including my implementation of the Twofish cipher algorithm, are handled by the BCrypt API layer.

5. CNG maps the custom Twofish algorithm identifier (separate from the above object identifier) back to Twofish.dll through the registry.  CNG then calls the BCRYPT_CIPHER_FUNCTION_TABLE interface I’ve enabled.  The specific BCrypt cipher functions that are used in this case include querying for the key object size (for the purpose of dynamically allocating memory for the key context), querying for the cipher block length (for the purpose of generating an IV), and then instantiating the key object.

6. Once the key handle has been returned to the underlying logic of CryptEncryptMessage, it’s used for its primary purpose: encrypting the message.  Therefore, the Twofish cipher function interface is exercised again with CNG/BCrypt.

Although the diagram above and corresponding description are more focused on encryption, message decryption works much the same way. The first difference is that, in step 2, the custom algorithm object identifier is embedded in the encrypted message, rather than specified as an explicit parameter to CryptDecryptMessage.  The second difference is that is that, in step 3, the CMSG_OID_CNG_IMPORT_CONTENT_ENCRYPT_KEY_FUNC is used to reconstitute the key object and decode the IV.

Implementation Details

In this section, I’ll highlight some of the important implementation details of the Twofish messaging cipher plug-in described above.  Architecturally, I’ll start from the bottom – the CNG plug-in – and end at the top – the test application.

CNG Cipher Plug-in Implementation

See twofish\CNG.cpp in the sample code that accompanies this article.  That’s the file that implements the BCRYPT_CIPHER_FUNCTION_TABLE interface.  In other words, it’s the crypto primitive plug-in for 256-bit Twofish.

There are a few interesting points to note about the cipher plug-in.  When an applications attempts to use the Twofish cipher, the first call to be received by this plug-in will be in response to BCryptOpenAlgorithmProvider.  Based on the information that the plug-in adds to the system registry, BCrypt will load twofish.dll and call GetCipherInterface (which must be provided as a named dll export).  In response, the plug-in returns a BCRYPT_CIPHER_FUNCTION_TABLE structure initialized with the addresses of its functions that implement the cipher interface (create a key, encrypt, decrypt, etc).  As an aside, note that the function table routines need not be implemented as DLL exports (my preference is to avoid doing anything that won’t be directly tested).  Moving on, my naming scheme for the function table routines is to replace the “BCrypt” at the beginning of each function table member with “TF” (for Twofish).  As a result, the second routine called (implicitly by the BCrypt dispatch layer) after GetCipherInteface is TFOpenAlgorithmProvider.

You’ll notice that most aspects of the Twofish CNG plug-in are quite simple.  TFOpenAlgorithmProvider is no exception.  It simply confirms that the requested algorithm name is “TWOFISH256” (see the #define for that string in the TFProv.h file), since that’s the only one it supports.  The plug-in doesn’t even require any context information to be stored in the returned BCRYPT_ALG_HANDLE, so it simply uses it as a pointer to the TWOFISH256 algorithm name string.  Downstream, for other interface routines that take that BCRYPT_ALG_HANDLE as input, I confirm that the handle still points to the string.  This is not a requirement, but it might help to catch otherwise subtle application bugs.

The next notable aspect of the CNG plug-in is the TFGetProperty routine, corresponding to BCryptGetProperty.  This function confused me at first, since one of its inputs is of type BCRYPT_HANDLE.  Depending on the scenario, the actual type of the handle provided by the caller in that parameter could be a BCRYPT_ALG_HANDLE or a BCRYPT_KEY_HANDLE.  This is different from previous versions of Crypto API, which provided separate CryptGetProvParam and CryptGetKeyParam functions for the same purpose.

To see one of the important uses of BCryptGetProperty, observe that BCryptGenerateSymmetricKey takes a buffer as input, allocated by the caller.  This is intended to be used to store whatever key context structure is required by the plug-in.  In other words, a typical symmetric cipher implementation (Twofish is in this category) need not make a single dynamic memory allocation!  This is a critical difference between CNG and legacy Crypto API.  Using the latter, crypto-intensive high-performance applications would frequently be artificially governed by contention on the process heap.

Anyway—moving on, in order to make a valid call into BCryptGenerateSymmetricKey, the application must first know how big to make the key object buffer.  In this situation, BCryptGetProperty is called with a BCRYPT_ALG_HANDLE and the BCRYPT_OBJECT_LENGTH property string.

In fact, the Twofish plug-in doesn’t implement a case in which BCryptGetProperty would require a BCRYPT_KEY_HANDLE (although see my implementation of TFSetProperty, which requires a BCRYPT_KEY_HANDLE in both cases).  What’s an example of such a case for GetProperty?  Consider anything that queries dynamic key context information, such as the current IV string or cipher mode.  I readily admit that I only implemented as much of the CNG cipher interface as was absolutely required to get the messaging sample to work!

Now take a look at TFEncrypt and TFDecrypt, which are really the whole point of a cipher plug-in!  In fact, these functions would be simple to implement, if it weren’t for the BCRYPT_BLOCK_PADDING flag.  That flag allows a calling application to optionally provide a plaintext input buffer to BCryptEncrypt that is not a multiple of the cipher’s block size in length (the flag has no meaning for anything other than a symmetric block cipher; however, Twofish happens to be one of the latter).

In order for the BCRYPT_BLOCK_PADDING flag to work correctly with BCryptDecrypt, at least one additional byte of padding must have been applied.  As a result, if the flag is specified, and the input plaintext is an exact multiple of the cipher block size in length, a full block of padding must be added during Encrypt.  The Twofish plug-in uses a standard padding scheme wherein the value of the padding bytes is equal to the length of the padding itself.  For example, Twofish uses a block size of 16 bytes.  A plaintext of length 6 bytes would be padded with 10 bytes of 0x0A if the BCRYPT_BLOCK_PADDING flag is specified (otherwise, TFEncrypt would return STATUS_INVALID_PARAMETER).  In summary, to support the padding flag, as well the general API usage of dynamically querying for the required output buffer size, parameter checking becomes somewhat complex for the Encrypt and Decrypt routines.

Rounding out the implementation of the CNG cipher plug-in are a few snippets of code in twofish\DllMain.cpp.  The BCryptRegisterProvider and BCryptAddContextFunctionProvider routines are used to register the implementation of the "TWOFISH256" algorithm.  This is done with DllRegisterServer, in support of “regsvr32.exe twofish.dll”.  Conversely, BCryptRemoveContextFunctionProvider and BCryptUnregisterProvider are called in response to DllUnregisterServer (i.e. through “regsvr32.exe /u twofish.dll”).

CMS Plug-in Implementation

Now that I’ve discussed the low-level foundation of the Twofish plug-in, I’ll move up the stack to the CMS portion of the plug-in. Overall, much like the CNG plug-in discussed above, the CMS piece seemed pretty obvious once I had it working, but there are just a few subtle tricks required in order to get to that point.

The twofish.dll binary exports just three functions:

· GetCipherInterface (required by CNG; see above)

· TFCngGenContentEncryptKey

· TFCngImportContentEncryptKey

The second two are the topic of this section, and are required in order to support use of any new cipher algorithm with CryptEncryptMessage and CryptDecryptMessage (as opposed to only enabling the algorithm with CNG, and not further up the stack, which would be kind of boring).  See the twofish\Capi2.cpp file– so named because these routines correspond to the Crypto API 2.0 portion of the application stack, of which CMS is a component.

TFCngGenContentEncryptKey

The first routine, TFCngGenContentEncryptKey, is of type CMSG_OID_CNG_GEN_CONTENT_ENCRYPT_KEY_FUNC, and allows a Twofish key and IV to be created and returned for bulk message encryption. The trick here is that the IV must accompany the message in order for the recipient to be able to decrypt it.  Therefore, the IV must be properly ASN.1 encoded as an OCTET STRING in order to adhere to the messaging standard.  Actually, this is just a matter of creating the 16 byte random IV, attaching it to the key context, and then encoding the 16 bytes with CryptEncodeObjectEx to be returned in the caller’s PCMSG_CONTENT_ENCRYPT_INFO-type input/output parameter.

TFCngImportContentEncryptKey

The second routine, TFCngImportContentEncryptKey, is of type CMSG_OID_CNG_IMPORT_CONTENT_ENCRYPT_KEY_FUNC.  It allows the encoded IV and decrypted Twofish key bytes to be restored as a BCRYPT_KEY_HANDLE, which is then used by crypt32.dll to decrypt the caller’s message via CNG.  First, the IV is decoded with CryptDecodeObjectEx.  Then the key is recreated by using the input key bytes, which have already been decrypted by crypt32.dll with the recipient’s private (RSA, in this example) key. A helper routine, _TFCngGenerateSymmetricKey, is shared between the two interface routines and is used to create a Twofish key handle from key bytes and an IV.

Finally, rounding out the CMS portion of the plug-in is the object identifier registration logic in DllMain.cpp. In terms of the code and structures required, this is only slightly more complex than the CNG registration logic discussed in the previous section.  First, the content encryption object identifier – szOID_TWOFISH256 (see #define in TFProv.h) – is added by using CryptRegisterOIDInfo.  Then, the two functions mentioned above are registered with CryptRegisterOIDFunction to map to twofish.dll.  The corresponding functions – CryptUnregisterOIDInfo and CryptUnregisterOIDFunction – are used in response to DllUnregisterServer.

Test Application Implementation

The previous two sections round out the discussion of the production portion of my customer deliverable.  This means that 256-bit Twofish can now be supported through my theoretical S/MIME application simply by registering twofish.dll on the client system.  However, let’s hope we never go into production without testing the new code first!

The TFTest.exe project that accompanies this article is such a test.  This test project performs three simple operations:

1. Create a test RSA key pair and recipient certificate.
Note: CryptDecryptMessage will fail in this scenario unless the key pair is CNG (as opposed to legacy Crypto API) based.  Why?  Well, in this scenario, it seems that Microsoft could have supported decryption of “unknown” symmetric key types with “raw” RSA decryption through the legacy API, but that they chose not to.  As a result, in the case of CNG-only plug-in symmetric ciphers, asymmetric key handles used for key agreement must also be CNG-based.

2. Encrypt a test message using CryptEncryptMessage, the test recipient certificate, and the szOID_TWOFISH256 content encryption identifier registered by twofish.dll.

3. Decrypt the test message using CryptDecryptMessage.

I have one final comment about the implementation of the test, although it is not directly related to the Twofish plug-in.  While CryptEncryptMessage takes an array of recipient certificates as input, CryptDecryptMessage takes an array of certificate stores as input. For the latter, each is searched for a matching recipient certificate.  Once the matching certificate is found, it must then be linked to the corresponding private key, which is used to decrypt the Twofish key in this case.  To accomplish this private key mapping, CryptDecryptMessage requires that the recipient certificate have either the CERT_KEY_PROV_INFO or CERT_KEY_CONTEXT property set.

However, the flow of the test program is such that this step is done for me.  In summary, the following APIs are used in sequence:

1. NCryptOpenStorageProvider – Open the MS_KEY_STORAGE_PROVIDER.

2. NCryptCreatePersistedKey – Initiate the creation of a new RSA key pair.

3. NCryptFinalizeKey – Create and store the new key pair.

4. CertStrToName – Encode a subject name for the test recipient certificate.

5. CertCreateSelfSignCertificate – Create the test recipient certificate and sign it with the NCRYPT_KEY_HANDLE created above. Private key mapping information, as described above, is attached to the returned certificate context.

6. CryptEncryptMessage – Described above.

7. CertOpenStore – Create an in-memory certificate store.

8. CertAddCertificateContextToStore – Add the recipient certificate context to the store.

9. CryptDecryptMessage – Described above.

Test Run-Time Analysis

I want to make a few comments about the behavior of the plug-in interfaces discussed above, based on my observations while debugging Twofish.dll and TFTest.exe.  I’ve mentioned that one of the major run-time enhancements in CNG versus the legacy API is its improved memory management.  In contrast, there were two things that surprised me about the performance of the CMS interface.

First, due partly to the fact that the CMS interface predates CNG, the former doesn’t fully implement the improved memory handling characteristics of the latter.  Specifically, in the test scenario implemented above, it would be nice if a high-performance solution could directly control all interaction with the heap, even at the messaging layer.  However, creation of the CNG key object is handled within crypt32.dll, and malloc- and free-type callbacks are not available to the application.

Second, I noticed that TFCngGenContentEncryptKey is called twice during a single call to CryptEncryptMessage.  The first call appears to be part of a length calculation in anticipation of building the encrypted message.  The call stack (from WinDbg.exe) follows:

0:000> k
ChildEBP RetAddr  
0012f908 754b6937 twofish!TFGenerateSymmetricKey
0012f938 10030f2a bcrypt!BCryptGenerateSymmetricKey+0x8a
0012fa74 10031247 twofish!_TFCngGenerateSymmetricKey+0x12a
0012fbbc 75793c97 twofish!TFCngGenContentEncryptKey+0x127
0012fbe0 7578da72 CRYPT32!ICM_CNGGenContentEncryptKey+0x34
0012fbf8 757891a9 CRYPT32!ICM_InitializeContentEncryptInfo+0xf2
0012fc7c 75789482 CRYPT32!ICM_LengthEnveloped+0x121
0012fca0 75766ef4 CRYPT32!CryptMsgCalculateEncodedLength+0x80
0012fcd4 75767241 CRYPT32!CryptHashMessage+0x6d6
0012fd50 0042eb4c CRYPT32!CryptEncryptMessage+0x64
0012ff34 00431042 TFTest!wmain+0x32c

A second call is made to TFCngGenContentEncryptKey, and this key is apparently used for the actual encryption.

0:000> k
ChildEBP RetAddr  
0012f920 754b6937 twofish!TFGenerateSymmetricKey
0012f950 10030f2a bcrypt!BCryptGenerateSymmetricKey+0x8a
0012fa8c 10031247 twofish!_TFCngGenerateSymmetricKey+0x12a
0012fbd4 75793c97 twofish!TFCngGenContentEncryptKey+0x127
0012fbf8 7578da72 CRYPT32!ICM_CNGGenContentEncryptKey+0x34
0012fc10 7578f593 CRYPT32!ICM_InitializeContentEncryptInfo+0xf2
0012fc80 75752352 CRYPT32!ICM_OpenToEncodeEnvelopedData+0x328
0012fca0 75766f34 CRYPT32!CryptMsgOpenToEncode+0x66
0012fcd4 75767241 CRYPT32!CryptHashMessage+0x716
0012fd50 0042ebde CRYPT32!CryptEncryptMessage+0x64
0012ff34 00431042 TFTest!wmain+0x3be

Better performance would be to build the key only once, or at least to expose a mode in the callback indicating that only size information should be returned and not a real key.

For completeness, I’ll mention that, for CryptDecryptMessage, the plug-in entry point is only exercised once, per the following call stack.

0:000> k
ChildEBP RetAddr  
0012f808 754b6937 twofish!TFGenerateSymmetricKey
0012f838 10030f2a bcrypt!BCryptGenerateSymmetricKey+0x8a
0012f974 100315a3 twofish!_TFCngGenerateSymmetricKey+0x12a
0012fab8 75793dff twofish!TFCngImportContentEncryptKey+0x123
0012fadc 7578e901 CRYPT32!ICM_CNGImportContentEncryptKey+0x34
0012fb04 7578ea76 CRYPT32!ICM_ImportContentEncryptKey+0x115
0012fb6c 757306de CRYPT32!ICM_ControlCmsDecrypt+0xb8
0012fba0 75767ca1 CRYPT32!CryptMsgControl+0x208
0012fc2c 7576811d CRYPT32!CryptVerifyMessageSignatureWithKey+0x816
0012fd10 75768295 CRYPT32!CryptSignAndEncryptMessage+0x392
0012fd54 0042eda6 CRYPT32!CryptDecryptMessage+0x2a
0012ff34 00431042 TFTest!wmain+0x586

The final overall debugging comment stems from some strange behavior I saw during my initial attempt to observe the test application from within WinDbg.exe (I don’t recall if the Visual Studio debugger had the same problem).  In summary, I wasn’t able to set breakpoints in twofish.dll.  The reason is this: as a pluggable object identifier handler for CMS, twofish.dll is imported with LoadLibrary using the standard path search logic – namely, first check for the DLL in the current directory, and then check system32. This behavior is Microsoft’s own best-practice recommendation from a serviceability perspective.

However, CNG will only load plug-ins from the system32 directory!  In other words, the current directory is never checked.  During the initial operation of my test, I had deployed twofish.dll to system32, but forgotten that a copy also existed in the test directory.  As a result, during the test run, CMS loaded the local copy and CNG loaded the one in system32.  And even though they were the same binary, the debugger was just as confused as me.  In summary, when testing your own applications in this scenario, don’t forget to first remove any local copy of the plug-in, and to always deploy an up-to-date version to system32.

Conclusion

Returning to the business problem that I started with, this implementation of the CNG and CMS plug-in points should address the customer’s need.  I can now support an arbitrary encryption algorithm (and specifically Twofish) in my secure messaging application.

One final note regarding the readiness of this sample to be turned into a truly production-quality deliverable: it has indeed been tested somewhat, but only with the CMS layer.  This means that no direct testing of the CNG cipher plug-in has been done.  While I’ve omitted this for the sake of brevity in the sample, no crypto algorithm implementation should go live in production without a barrage of direct testing, including with known-good plaintext/ciphertext pairs obtained from a separate implementation.

Acknowledgements: I’d like to thank Andrew Tucker and Kelvin Yiu at Microsoft for their technical feedback pertaining to this article.

Appendix A – CNG: Kicking the Tires

Let me speak philosophically for a moment about Windows APIs in general.  When, during the course of a project, I need to ramp up on a new API set, I tend to mentally classify the APIs in two ways.  The first class consists of those routines that report or enumerate existing data.  The second class consists of those that create or change something.  Not rocket science, right?  In my experience, the first class – reporting and enumerating data – is generally easier to get working correctly.  But the second class – creating or changing something – is the reason I’m learning the API in the first place.  Taking the time to learn about the first class of APIs tends to bring some insight into how the second class works, potentially shortening the learning curve in the long run.  This is a leap of faith, though, because what I really want to do is just get my project – whatever it is – working.  Hence, I dive directly into the harder APIs and get stuck!

So for CNG, I started by creating a test program that enumerates everything made available by the API.  The test creates some things, too – namely, persisted private keys – but only to make the enumeration part more interesting.  The test program is available for download. Here’s the output from my Windows Vista laptop:

>CngEnum.exe
Microsoft Primitive Provider - CNG registration information
Interface = 1 (BCRYPT_CIPHER_INTERFACE)
 User-mode:
  Functions: RC2, RC4, AES, DES, DESX, 3DES, 3DES_112
 Kernel-mode:
  Functions: RC2, RC4, AES, DES, DESX, 3DES, 3DES_112
Interface = 2 (BCRYPT_HASH_INTERFACE)
 User-mode:
  Functions: MD2, MD4, MD5, SHA1, SHA256, SHA384, SHA512
 Kernel-mode:
  Functions: MD2, MD4, MD5, SHA1, SHA256, SHA384, SHA512
Interface = 3 (BCRYPT_ASYMMETRIC_ENCRYPTION_INTERFACE)
 User-mode:
  Functions: RSA
 Kernel-mode:
  Functions: RSA
Interface = 4 (BCRYPT_SECRET_AGREEMENT_INTERFACE)
 User-mode:
  Functions: DH, ECDH_P256, ECDH_P384, ECDH_P521
 Kernel-mode:
  Functions: DH, ECDH_P256, ECDH_P384, ECDH_P521
Interface = 5 (BCRYPT_SIGNATURE_INTERFACE)
 User-mode:
  Functions: DSA, ECDSA_P256, ECDSA_P384, ECDSA_P521, RSA_SIGN
 Kernel-mode:
  Functions: DSA, ECDSA_P256, ECDSA_P384, ECDSA_P521, RSA_SIGN
Interface = 6 (BCRYPT_RNG_INTERFACE)
 User-mode:
  Functions: RNG, FIPS186DSARNG
 Kernel-mode:
  Functions: RNG, FIPS186DSARNG
 
Microsoft Software Key Storage Provider (Comment: (null))
Algorithms:
 Name: RSA  [Class = 3, Operations = 20, Flags = 0]
 Name: DH  [Class = 4, Operations = 8, Flags = 0]
 Name: DSA  [Class = 5, Operations = 16, Flags = 0]
 Name: ECDH_P256  [Class = 4, Operations = 24, Flags = 0]
 Name: ECDH_P384  [Class = 4, Operations = 24, Flags = 0]
 Name: ECDH_P521  [Class = 4, Operations = 24, Flags = 0]
 Name: ECDSA_P256  [Class = 5, Operations = 16, Flags = 0]
 Name: ECDSA_P384  [Class = 5, Operations = 16, Flags = 0]
 Name: ECDSA_P521  [Class = 5, Operations = 16, Flags = 0]
Implementation Type: 2
User keys:
 Name: CNG_Test_RSA_Key
  Alg = RSA, Flags = 0, KeySpec = 1, Size: 1024
 Name: CNG_Test_ECDH_Key
  Alg = ECDH_P521, Flags = 0, KeySpec = 0, Size: 521
 Name: CNG_Test_ECDSA_Key
  Alg = ECDSA_P521, Flags = 0, KeySpec = 0, Size: 521
 Name: TFTest_Key
  Alg = RSA, Flags = 0, KeySpec = 1, Size: 1024
 Name: CNG_Test_DSA_Key
  Alg = DSA, Flags = 0, KeySpec = 2, Size: 1024
 Name: CNG_Test_DH_Key
  Alg = DH, Flags = 0, KeySpec = 1, Size: 768
Machine keys:
 Name: CNG_Test_RSA_Key
  Alg = RSA, Flags = 0, KeySpec = 1, Size: 1024
 Name: CNG_Test_ECDH_Key
  Alg = ECDH_P521, Flags = 0, KeySpec = 0, Size: 521
 Name: CNG_Test_ECDSA_Key
  Alg = ECDSA_P521, Flags = 0, KeySpec = 0, Size: 521
 Name: CNG_Test_DSA_Key
  Alg = DSA, Flags = 0, KeySpec = 2, Size: 1024
 Name: CNG_Test_DH_Key
  Alg = DH, Flags = 0, KeySpec = 1, Size: 768
 
Microsoft Smart Card Key Storage Provider (Comment: (null))
Algorithms:
Implementation Type: 11
User keys:
 
Microsoft Enhanced Cryptographic Provider v1.0 - User Keys:
 CNG_Test_RSA_Key
 bf1eed19-d3cf-40ce-b500-15ae65a347b7
 le-User-df0836fb-bc75-4c74-b453-1cbc002778a2
 a7baa3a8-7561-4972-be93-53c1960181c5
 dan
 TestContainerForCngEnum
 
Microsoft Enhanced Cryptographic Provider v1.0 - Machine Keys:
 CNG_Test_RSA_Key
 TestContainerForCngEnum
 
Microsoft Enhanced DSS and Diffie-Hellman Cryptographic Provider - User Keys:
 dan
 TestContainerForCngEnum
 
Microsoft Enhanced DSS and Diffie-Hellman Cryptographic Provider - Machine Keys:
 dan
 TestContainerForCngEnum
Success

Appendix B – System Components Using CNG

When I started working on this article, I wasn’t certain if many components of the operating system had been ported to use CNG, or if most of the crypto consumers were still using the previous version of the API.  A few simple scripts and debugging tools helped to answer that question.

Based on the CNG documentation, I knew that any component calling CNG would have a dependency on either bcrypt.dll or ncrypt.dll. The first step was to locate the processes running in Windows Vista with either of those DLLs loaded.  Having recently seen a presentation by Mark Russinovich of Sysinternals, I knew that his Process Explorer tool would be able to provide this information.  However, my preference in this case was for a command-line based tool.  It turns out that Sysinternals provides one: ListDlls (see the Resources section for download information). Using that tool, here’s what I found:

>c:\temp\Listdlls.exe -d ncrypt.dll | findstr /i pid
lsass.exe pid: 608
svchost.exe pid: 944
svchost.exe pid: 1080
svchost.exe pid: 1504
sqlservr.exe pid: 516
taskeng.exe pid: 2352
taskeng.exe pid: 3760
OUTLOOK.EXE pid: 2588
cmd.exe pid: 3664
iexplore.exe pid: 2908
iTunes.exe pid: 5756

In analyzing the tool output, I knew I was discovering something interesting when I realized that even iTunes is using CNG!  I then realized that there must be a more common dependency among those applications, which in turn has a dependency on CNG.  What’s the common dependency?  Starting iTunes in a debugger shows it easily enough.

>windbg.exe -g -c "sx eld:ncrypt.dll ; k20" -y srv*c:\Symbols*http://msdl.microsoft.com/do
wnload/symbols "c:\Program Files\iTunes\iTunes.exe"
 
ChildEBP RetAddr 
…
0012ebcc 7575ed3d kernel32!LoadLibraryA+0xb7
0012ec10 7575edad CRYPT32!__delayLoadHelper2+0x55
0012ec4c 75763b44 CRYPT32!_tailMerge_ncrypt_dll+0xd
0012ec70 7575ee20 CRYPT32!I_CryptGetCNGAlgorithmProvider+0x5b
0012ec84 7575f0e1 CRYPT32!I_CryptGetCNGHashProvider+0x11
0012ec9c 7575f90c CRYPT32!ICM_CreateHash+0x34
0012ecc0 7575fb89 CRYPT32!ICM_CreateHashList+0x6d
0012ed20 7575fda6 CRYPT32!ICM_UpdateDecodingSignedData+0x8c
0012ed74 74f88837 CRYPT32!CryptMsgUpdate+0x1d6
0012eda8 74f8373c WINTRUST!_GetMessage+0x18b
0012edc0 74f83615 WINTRUST!SoftpubLoadMessage+0x75
0012eed8 74f8346c WINTRUST!_VerifyTrust+0x22d
0012eefc 005c1695 WINTRUST!WinVerifyTrust+0x50
0012ef38 775d17ab iTunes+0x1c1695

Now we know the common dependency: WinVerifyTrust, the Win32 function that provides certificate-based digital signature checking.  That routine loads crypt32.dll, which in turn takes a delay load dependency on ncrypt.dll, a fact that can also be confirmed via your favorite “Portable Executable” binary dumper:

>link.exe /dump /imports c:\Windows\System32\crypt32.dll
…
 Section contains the following delay load imports:
…
    ncrypt.dll

While it’s interesting that the operating system’s signature checking logic is now based on CNG rather than legacy Crypto API, I was also interested to learn that Microsoft has not yet exposed pluggable signature algorithm support via WinVerifyTrust (i.e. that API is not crypto-agnostic).  So why did they bother to port it over the CNG then?  I don’t know for sure, but I speculate that one goal of the Vista release was to make the entire crypto stack CNG-based by default.

Appendex C – Additional Resources

About the Author

Dan Griffin is a software security consultant in Seattle, WA.  He previously spent seven years at Microsoft on the Windows Security development team.  Dan can be contacted at http://www.jwsecure.com.

this is draft content and is subject to change

Download RDCSample.exe.

Dependencies
You must have the Windows SDK for Windows Vista. If you do not install the SDK to the default location, which is listed below, you must update the Visual Studio Include and Library paths in the sample code accordingly. Download the Windows SDK for Windows Vista. The Windows Vista SDK installs to %ProgramFiles%\Microsoft SDKs\Windows\v6.0.

Summary

This code sample demonstrates the use of the Microsoft Remote Differential Compression COM interfaces in a .NET environment using C#. This sample code requires the .NET Framework 2.0 and Microsoft Vista or Windows 2003 R2 at run time.

The following Visual Studio 2005 projects are included in the download:

Microsoft.RDC

This project is the managed core API and wrapper around the native RDC API. This is the main project that provides the RDC features. This project can be consumed via other managed applications to make use of RDC. This project also contains all of the marshaling logic between the managed and COM interfaces.

To use this API in your projects, add the compiled assembly as a reference.

RdcWebService

This project is a web service that provides the following functionality: server-side signature generation, and transfer of RDC signatures and file block fragments.

Client

This project interfaces with the RdcWebService and demonstrates how to consume an RDC service over HTTP using .NET. The client is a basic console application that takes the following arguments.

USAGE: client.exe -u remoteUrl remoteFile(source) localFile(seed) targetFile(output)

Arguments:
-u          Absolute URL to the remote RDC Web Service.
remoteFile  Absolute path to the remote file.
localFile   Absolute path to the local seed file.
targetFile  Absolute path to the local target file.  This is the output.

More Information and Errata

For more information, please see the latest Windows SDK documentation. A separate, purely native-code based RDC sample is described in the SDK in Samples\WinBase\RDC\Readme.txt.

We will publish bugs and errata at http://www.jwsecure.com/dan/index.html. Please report new bugs by contacting JW Secure at http://www.jwsecure.com/contact.html.

this is draft content and is subject to change

Download IPsecPingSample.exe.

Dependencies
You must have the Windows SDK for Windows Vista. If you do not install the SDK to the default location, which is listed below, you must update the Visual Studio Include and Library paths in the sample code accordingly. Download the Windows SDK for Windows Vista. The Windows Vista SDK installs to %ProgramFiles%\Microsoft SDKs\Windows\v6.0.

The following Visual Studio 2005 project is included in the download:

PingS

This project produces IPSecPing.exe, an IPsec debugging tool. This is a socket-based client application, adapted from an existing Windows SDK sample (securesocket), with the following primary extensions:

  1. To facilitate the debugging of the IPsec policy existing between two computers, a more usable console display is now available. See the -v (verbose) flag. For example:
    >IPSecPing.exe -v  -4 peermachine2
    Create socket , return code=0
    TCP over IPsec connect to dest: peermachine2, addr 192.168.1.184:135...
    TCP over IPSec WSAConnect: success, 0.01s from 192.168.1.102:49359 to 192.168.1.184:135
    IKEMM: 3DES, SHA1, DH_2, Kerberos, 28800s, 192.168.1.102, 192.168.1.184, icookie=0x1a712494, rcookie=0xde0efd89
    IKEQM: transport, SHA1, 3DES, 100000kb, 3600s, 192.168.1.102, 192.168.1.184, idletime=300s
    Disconnecting, IKE MM and QM deleted
    The following is the tool output in IPv6 mode, connecting to the "securesocket" (stcpserver.exe) sample from the Windows SDK:
    >IPSecPing.exe -v  -6 -p 27015 peermachine2
    Create socket , return code=0
    TCP over IPsec connect to dest: peermachine2, addr [fe80::7449:86cb:9e9e:d6ab%8]:27015...
    TCP over IPSec WSAConnect: success, 0.11s from [fe80::fdf4:318:76ad:36dd%8]:49356 to [fe80::7449:86cb:9e9e:d6ab%8]:27015
    IKEMM: AES-128, SHA1, DH_ECP_256, Anonymous, Kerberos, 7200s, [0:2:0:1770c8:1d24:c8:1d14], [7681:7b1c:0:20:1770:c8:1d24], icookie=0x111023c9, rcookie=0x74210bda
    IKEQM: transport, SHA1, AES-128, 56320kb, 3600s, [0:2:0:1770c8:1374:c8:1364], [7681:7b1c:0:20:1770:c8:1374], idletime=300s
    Disconnecting, IKE MM and QM deleted
  2. A separate server-side debugging tool is no longer required. Instead, the client attempts by default to connect to the server RPC end-point mapper.
  3. Optionally, you can specify an alternate connect-to port at the command-line.

More Information and Errata

This sample was co-developed by William Dixon of V6 Security, Inc. (http://www.v6security.com) and Dan Griffin of JW Secure, Inc. For more information, please see the MSDN online article which accompanies this sample. We will publish bugs and errata at http://www.jwsecure.com/dan/index.html. Please report new bugs by contacting JW Secure at http://www.jwsecure.com/contact.html.

this is draft content and is subject to change

Dan Griffin
JWSecure, Inc.

May 2007

Summary: This whitepaper and accompanying sample demonstrates how to program the new Windows Firewall API including how to configure the Windows Firewall for correct operation with. (22 printed pages). Download XPS version.

Download the associated sample code, FirewallSample.exe.

Dependencies
You must have the Windows SDK for Windows Vista. If you do not install the SDK to the default location, which is listed below, you must update the Visual Studio Include and Library paths in the sample code accordingly. Download the Windows SDK for Windows Vista. The Windows Vista SDK installs to %ProgramFiles%\Microsoft SDKs\Windows\v6.0.

Introduction

I’m Dan Griffin of JW Secure, Inc, and this is the second in a series of articles that I’m writing about some of the new cool security features in Microsoft® Windows Vista. The first article demonstrated how to add a new symmetric cipher algorithm to “Crypto API: Next Generation” (CNG) and the Cryptographic Message Syntax (CMS) APIs. Future articles and sample code will address the topics including IPsec, IPv6, the smart card module minidriver interface, and fuzz testing (using malformed data input for testing).

The focus of this article is to demonstrate the recommended use of the new Windows Firewall API. Specifically, I show how to program Windows Firewall from the perspective of an independent software vendor (ISV) that wishes to configure its network-based application with a restrictive-as-possible firewall rule set. A complete set of code samples accompanies this article, including a demonstration socket-based client/server program and a firewall tool that shows how to programmatically add and remove firewall rules.

Firewall and Filtering Architecture

Before I get to the discussion of the sample code, there are two other items of business to address. First, I want to provide pointers to existing documentation and background information that every programmer should peruse prior to using the Windows Firewall API.

The second item of business to address before I get to the sample code is to briefly explain the difference between the Windows Filtering Platform and the Windows Firewall APIs.

My sample demonstrates the use of two closely related Windows Vista APIs – those for the Windows Filtering Platform and those for the Windows Firewall. The Windows Filtering Platform API is new in Windows Vista. While some of the Windows Firewall API functionality is available in Windows XP, it has been greatly enhanced in Windows Vista. And while some of the capabilities of the Windows Filtering Platform and Windows Firewall APIs overlap in Windows Vista, it’s important to understand the scenarios to which each applies.

I learned this lesson the hard way since my first attempt to programmatically add firewall rules for my sample TCP server was based on the Windows Filtering Platform API. This was partly because I first found a sample in the latest SDK that demonstrates adding Windows Filtering Platform-based rules for MSN Messenger. Since I had no reason to suspect that this wouldn’t be a good starting point for my own work, I used it as a baseline. Using the Windows Filtering Platform API instead of the Windows Firewall API was also initially attractive because I found the Windows Filtering Platform API to be more intuitive.

However, while testing my first Windows Filtering Platform-based solution, I found that even after adding my filters, I was still getting prompted by the Windows Firewall when the TCP socket-based test server program started listening on its port. Windows Vista displayed the screenshot below when I was testing my first Windows Filtering Platform-based solution.

Figure 1 – Windows Security Alert

Furthermore, my Windows Filtering Platform rules seemed to be ignored. If I clicked the Keep blocking button, the client could never connect, regardless of my own filter. If I clicked the Unblock button, the server was able to receive all traffic, regardless of the client address, for example, even though my filter was more restrictive. In other words, despite the presence of my filter, I was still observing the default per-application behavior of the Windows Firewall.

This was contrary to my goals for this demo since I wanted to demonstrate the proper way to install very specific firewall rules and to avoid the above potentially confusing dialog box.

Subsequent conversation with the engineering team at Microsoft clarified that the Windows Filtering Platform API is not intended to be used in the way I was using it. In scenarios where the Windows Firewall is enabled, and a standard network based application needs to open one or more ports, the Windows Firewall API should be used. In contrast, the primary purpose of the Windows Filtering Platform API is to facilitate development of rule-based network infrastructure technologies, such as 3rd party firewalls. Indeed, the Windows Firewall is based on the Windows Filtering Platform API, as I’ll demonstrate below, and non-Microsoft firewalls are intended to be so as well.

We can infer from this situation that it’s Microsoft’s intent that the average network application should not interact with the Windows Filtering Platform API in any way. Rather, such applications should call into the higher-level Windows Firewall APIs during installation and un-installation. This is best practice since the Windows Firewall is enabled by default. However, application developers should also provide documentation detailing the expected firewall rules configuration for proper and secure operation. This is important since the Windows Firewall may have been replaced by a non-Microsoft solution (and, therefore, a different programmatic interface). Finally, this should serve as a gentle reminder that Windows should always have a software firewall enabled and correctly configured!

Sample Business Problem

Let’s consider a specific example in order to motivate the discussion of the Windows Firewall API. Suppose, at a large manufacturing enterprise, one business group maintains an internal software application that stores customer information, including some sensitive data like credit card and social security numbers. Suppose, further, that to create synergy across the organization, another business group must now have access to the same data.

As the in-house developer in charge of this line of business application, suppose I’ve been asked to confirm that it’s sufficiently robust for the new demands that will be placed on it, including the need for additional users and increased exposure of the sensitive data to the corporate network.

Considering the problem in a somewhat broader sense, depending on the internal network security policies of the organization, such an application may be hosted on a server that is itself protected by a 3rd party firewall solution. The following items may compound the problem:

    • Administrative access to the server may be tightly controlled and audited.
    • The application architecture may be three-tier, with the data hosted off-box.
    • IPsec policies may be in place to protect network traffic, at least between the application and database servers.

These are all good things. However, additional defense-in-depth measures are recommended. To put it another way, as a software developer, I shouldn’t assume that security mechanisms beyond my direct control, such as a hardware-based firewall, are present or configured correctly. This is where a discussion of the Windows Firewall becomes interesting. In the context of this example, the objective is to configure the software firewall under the assumption that it’s the last defense standing between an army of bad guys and the sensitive customer data. Realistically, leveraging the security mechanisms offered by the underlying platform is especially important in light of the fact that many organizations lack the resources to deploy the additional security mechanisms mentioned above.

In summary, I know that two business groups will be accessing sensitive customer data from the corporate network via my application. Although the following discussion will focus only on configuring the software firewall, in reality, other aspects of the security design of the application need to be considered. For example, has the code recently undergone a thorough security review?

With these requirements in mind, let’s take a look at some sample code.

Sample Code: Introduction

In the example scenario I described above, I’m a developer who’s been asked to prepare an existing line of business application for broader use in a corporate network. In this article, my intent is to use this scenario to demonstrate the use of the new, improved version of the Windows Firewall API. It bears mentioning that this implies that the application is hosted on Windows Vista or a later version of Windows. Admittedly, this is more of a server scenario, and will be more relevant once the next version of Windows Server (codename Longhorn) is released. I’m not aware of any plans to port the new Windows Firewall API down-level.

A portion of the sample code accompanying this article is based on a pre-existing sample from the Windows Vista version of the Windows SDK (formerly known as the Platform SDK). The original sample code for the TCP server application can be found in the “Samples\NetDs\winsock\securesocket” subdirectory of the SDK installation. The original code included some logic pertaining to IPsec and IPv6, which I’ve intentionally disabled or removed in order to limit the scope of this particular discussion. Future articles in this series will include a complete analysis of introducing those technologies into the context of a similar sample.

More Windows Firewall related sample code also accompanies the latest Windows SDK. See the “Samples\Security\WindowsFirewall” subdirectory.

Firewall Rules

I mentioned in the beginning of this article that I was initially confused about the difference between the Windows Firewall API and the Windows Filtering Platform APIs. Once I understood how to access the firewall, I became quite impressed with its simplicity of use. A firewall rule includes configurable conditions for a variety of network traffic characteristics (ports, addresses, etc). A rule must specify an action – Allow or Block. Therefore, in order for an Allow rule to apply, each of its conditions must be met.

This is exactly the behavior that I want to apply in my sample code. Namely, the application is opening a socket on the server and waiting for clients to make requests. By default, the application is listening on a port that I expect to be blocked by the Windows Firewall. I want to cause the firewall to open that port, but to only allow network traffic through that meets certain conditions. I also want to make those conditions as restrictive as possible. Any traffic that doesn’t meet every filter condition should never be able to access my application. This is an important security concept – the default answer for inbound packets that wish to traverse the firewall, even when my application is listening on its port, is still “No”!

Ultimately, the appropriate set of filter conditions will vary for each application and deployment. Bearing in mind, again, that the rule or rules should be as restrictive as possible, I’ll attempt to create a representative set of conditions in this example. In this case, I don’t want to accept any traffic unless it meets all of the following conditions.

  1. The protocol in use is TCP/IP. For example, we won’t accept UDP traffic.
  2. The destination port is the specific one upon which my application is listening.
  3. The client address is of an expected range. 

    - Given that I’m only testing this example with IPv4 addresses, this condition is easy to implement for small organizations, especially those using NAT. In those cases, the client address condition might stipulate 192.168.1.0 with the corresponding mask of 255.255.255.0. 

    - For organizations with multiple non-contiguous address ranges, managing the configuration of this rule is a little tougher, but certainly not impossible.
  4. Finally, as an added bonus, I’d like to ensure that the above rule only applies to my specific application, and only when it’s running. That is, I don’t want another process on the host server to be able to receive my traffic, intentionally or otherwise.

Implementation of the Sample Firewall Rule

As I mentioned above, a Windows Firewall API rule exposes a variety of optional conditions. Programmatically, the conditions are exposed as properties of the INetFwRule interface. In fact, the available set of properties is sufficiently expressive that the desired behavior of the sample socket application can be achieved with a single rule. That’s exactly what I hoped for: conceptually, I want to open a port as well as enable a specific application to listen on it, but only to certain types of traffic. It’s easy to imagine how a rules engine requiring two separate rules to implement that behavior might in fact not be able to achieve it. For example, the resulting filters could be overly permissive due to a port being open but not bound to a specific application. I’ll show how to test for such situations in the next section.

In the meantime, here’s the code that creates the rule and enables it on the host. The function is WFAddRule, and it is part of my FwTool.exe utility. I’ll discuss this utility in more detail in the Testing section.

#import "netfw.tlb"

// Add settings for the demo server application to the Windows Firewall

DWORD

WINAPI

WFAddRule(

__in LPWSTR wszServerAppName,

__in LPWSTR wszServerAppFullPath,

__in LPWSTR wszFirewallGrouping,

__in NET_FW_IP_PROTOCOL fwIpProtocol,

__in LPWSTR wszRemoteAddresses,

__in LPWSTR wszLocalPort)

{

HRESULT hr = S_OK;

long lCurrentProfileTypes = 0;

WCHAR rgwszDescription [256];

try

{

// Retrieve the active policy

NetFwPublicTypeLib::INetFwRulePtr sipFwRule;

NetFwPublicTypeLib::INetFwPolicy2Ptr sipFwPolicy2AsAdmin;

CHECK_COM2(_CoCreateInstanceAsAdmin(

GetDesktopWindow(),

__uuidof(NetFwPolicy2),

IID_PPV_ARGS(&sipFwPolicy2AsAdmin)));

lCurrentProfileTypes = sipFwPolicy2AsAdmin->CurrentProfileTypes;

// Create a new rule

CHECK_COM2(sipFwRule.CreateInstance("HNetCfg.FwRule"));

// Build and set the rule description string

CHECK_COM2(StringCbPrintf(

rgwszDescription,

sizeof(rgwszDescription),

L"Allow network traffic for %s",

wszServerAppName));

sipFwRule->Description = rgwszDescription;

// Set the remaining rule properties

sipFwRule->Name = wszServerAppName;

sipFwRule->ApplicationName = wszServerAppFullPath;

sipFwRule->Protocol = fwIpProtocol;

sipFwRule->LocalPorts = wszLocalPort;

sipFwRule->RemoteAddresses = wszRemoteAddresses;

sipFwRule->Grouping = wszFirewallGrouping;

sipFwRule->Profiles = lCurrentProfileTypes;

sipFwRule->Action = NetFwPublicTypeLib::NET_FW_ACTION_ALLOW;

sipFwRule->Enabled = VARIANT_TRUE;

// Add the new rule to the active policy (effective immediately)

CHECK_COM2(sipFwPolicy2AsAdmin->Rules->Add(sipFwRule));

}

catch(_com_error& e)

{

hr = e.Error();

}

return (DWORD) hr;

}

There are a few things to note about the above sample code. First, for the sake of brevity, I’ve omitted the definition of two dependencies of this function. One is the error-checking macro CHECK_COM2, which simply prints a debug string and throws an exception if the wrapped COM call fails. The other is the helper routine _CoCreateInstanceAsAdmin, which is essentially the same as the routine documented in the SDK in the COM Elevation Moniker section (see http://msdn2.microsoft.com/en-us/ms679687.aspx).

The next thing to note about the code is that, although I’m using the Windows Firewall COM classes via C++, I’m avoiding some of the usual interoperability nastiness (e.g. explicitly converting LPWSTRs to BSTRs) by using the “netfw.tlb” interop library included with the SDK.

With those general comments in mind, I’ll run through the main purpose of the routine – adding the firewall rule for my demo server application. Here’s an explanation of each property in turn.

Property

Description

Description

A diagnostic field, visible programmatically and via the Firewall MMC snap-in (see below).

Name

Take another look at the Windows Security Alert dialog box screen shot in the previous section. Notice that the default firewall behavior is to use the program binary, without the extension (.exe), as its rule name. I’ll discuss this behavior in more detail below. In the meantime, the caller of my WFAddRule function is expected to provide that string (“stcpserver” in this case) as the first parameter.

ApplicationName

This property should be set to the full path of the server application binary. By using this property, I’m preventing a binary at any other location in the file system from listening on my port.

Protocol

See the NET_FW_IP_PROTOCOL enumerated type in the public icftypes.h header. Defined values correspond to TCP, UDP, and ANY. This example uses this property to restrict allowed traffic to TCP.

LocalPorts

Specifies the port upon which my application is allowed to listen. For handling more complex scenarios, a comma-delimited list of ports may be used instead (see http://msdn2.microsoft.com/en-us/library/aa365362.aspx).

RemoteAddresses

During testing, I’m typically using this property to specify a single address on my test LAN, in order to ensure that the test client is allowed or blocked as appropriate. For deployment, more sophisticated use of this property will be required – it can take a variety of interesting values – see http://msdn2.microsoft.com/en-us/library/aa365366.aspx.

Grouping

This property should be used to specify a common group name for all rules that apply to a given application or feature. This demonstration only requires a single rule, so the value of this property is diminished. However, its presence allows an administrator to enable, disable, and remove rules using group name rather than having to do this for each individually. The syntax of this property allows the value to be retrieved using a resource table, which facilitates localization. The sample code that accompanies this article demonstrates this “indirect string” configuration. A difficult-to-diagnose error (INetFwRules.Add returns 0x80004005) occurs if the indirect string is incorrectly configured; keep in mind that it must be loaded from system32.

Profiles

This property indicates the policy profile(s) in which the rule should apply. For the list of possible values, see the NET_FW_PROFILE_TYPE2 enumerated type in icftypes.h. Note the behavior of my test program which installs this rule – it specifies that the new rule should apply in whichever profiles are in effect at the time of installation. However, if the server needs to be able to run under a different profile (e.g. Domain vs. Public), then this logic will need to be modified accordingly.

Action

This property is simple to understand: a given rule either blocks traffic or allows it. This example does the latter.

Enabled

Another straightforward property: a rule can be present but disabled. However, I want my rule to be enabled immediately, so this property is set to “True”.

In summary, creating and applying the rule is not a complex task. Once the rule is in effect, though, it needs to be tested. This presents a more interesting challenge, and is the topic of the next section.

Testing

Installing the Firewall Rule and Running the Demo

As I mentioned in the discussion about the WFAddRule function, that code is part of the FwTool.exe command-line utility that accompanies this article. The utility has three modes of operation, as displayed in its console “usage” output:

>FwTool.exe

Usage:

FwTool.exe ADD -n <ServerAppName> -p <Port> -a <ClientAddressRange>

FwTool.exe DELETE -n <ServerAppName>

FwTool.exe SHOW -n <ServerAppName>

In other words, the first option allows the firewall rule (as discussed in the previous section) to be created based on the specified server application name, server port, and allowed client address range. The second option allows the rule to be deleted. The third option displays the resulting Windows Filtering Platform filters that are created by the firewall under the covers.

To configure the server-side of the test (mine is named “testmachine6”), copy stcpserver.exe and fwtool.exe to the system32 directory (although you can see in the sample filter output in the next section that I was running both programs from a directory called test at the root of the volume). Then, add a rule for stcpserver in the firewall by using FwTool. For example, the following command will allow only the client at a specific IP address to connect:

>FwTool.exe ADD -n stcpserver -p 27015 -a 192.168.1.192

Success

Run stcpserver.exe on the server-side host machine, as shown in the following command. Since its rule has already been added to the firewall, you shouldn’t see a Windows Security Alert dialog box.

>stcpserver.exe

Listening on socket bound to 0.0.0.0:27015 ...

Run stcpclient on the client-side host machine, as shown in the following command. The server DNS name must be specified on the command-line. Since this client is the one allowed by the installed firewall rule, it immediately connects, exchanges some data with the server, and disconnects.

>stcpclient.exe testmachine6

Secure connection established to the server

Sent 8 bytes of data to the server

Received 11 bytes of data from the server

Finished

Here’s the additional output displayed by the server in response to the client-connect and data-exchange. Then the server re-listens on its socket.

>stcpserver.exe

Listening on socket bound to 0.0.0.0:27015 ...

Connected to a client

Received 8 bytes of data from the client

Sent 11 bytes of data to the client

Listening on socket bound to 0.0.0.0:27015 ...

Displaying the Resulting Filters

>FwTool.exe SHOW -n stcpserver

Filter Name: stcpserver, Action: 0x1002, Effective Weight: 0xd92fd4

SubLayer: Windows Firewall, Weight: 2

Match Field: IP_LOCAL_PORT, Type: 0, Value: 27015

Match Field: APP_ID, Type: 0, Value:

0000 5c 00 64 00 65 00 76 00 69 00 63 00 65 00 5c 00 \.d.e.v.i.c.e.\.

0010 68 00 61 00 72 00 64 00 64 00 69 00 73 00 6b 00 h.a.r.d.d.i.s.k.

0020 76 00 6f 00 6c 00 75 00 6d 00 65 00 34 00 5c 00 v.o.l.u.m.e.4.\.

0030 74 00 65 00 73 00 74 00 5c 00 73 00 74 00 63 00 t.e.s.t.\.s.t.c.

0040 70 00 73 00 65 00 72 00 76 00 65 00 72 00 2e 00 p.s.e.r.v.e.r...

0050 65 00 78 00 65 00 00 00 e.x.e...

Filter Name: stcpserver, Action: 0x1002, Effective Weight: 0xd96f8c

SubLayer: Windows Firewall, Weight: 2

Match Field: IP_LOCAL_PORT, Type: 0, Value: 27015

Match Field: APP_ID, Type: 0, Value:

0000 5c 00 64 00 65 00 76 00 69 00 63 00 65 00 5c 00 \.d.e.v.i.c.e.\.

0010 68 00 61 00 72 00 64 00 64 00 69 00 73 00 6b 00 h.a.r.d.d.i.s.k.

0020 76 00 6f 00 6c 00 75 00 6d 00 65 00 34 00 5c 00 v.o.l.u.m.e.4.\.

0030 74 00 65 00 73 00 74 00 5c 00 73 00 74 00 63 00 t.e.s.t.\.s.t.c.

0040 70 00 73 00 65 00 72 00 76 00 65 00 72 00 2e 00 p.s.e.r.v.e.r...

0050 65 00 78 00 65 00 00 00 e.x.e...

Match Field: IP_REMOTE_ADDRESS, Type: 0, Value:

Addr = 192.168.1.192

Mask = 0.0.0.0

Match Field: IP_PROTOCOL, Type: 0, Value: 6

Success

The Windows Firewall MMC Snap-In

Windows Vista includes a built-in firewall management console, which I found (along with FwTool.exe) to be a useful way to check my work as I was developing and testing the rule code discussed in the previous section. To access the console, click Start, type “WF.msc” into the Start Search box, and then press Enter. I started by selecting Inbound Rules in the left pane. It’s educational to examine the rules that are present by default.

Once my custom rule was added by using FwTool, as described above, I selected Filter by Group in the Actions pane on the right. Sure enough, one of the listed options is the TCP Server demo group created by my code. Selecting that option, and then adjusting the widths of some of the display fields, allowed me to grab the following screenshot.

Figure 2 - Windows Vista Firewall Management Console

In the center pane of the above screenshot, all of the expected properties of the custom rule are present (including a number of fields that I’m not showing since the image would have been too wide). For example, the host machine is a member of a test (Active Directory) domain, and was on that network (that is, as opposed to a roaming laptop connected to public Wi-Fi) at the time that the rule was added. Therefore, the rule is applied in the Domain profile. Also, note that I configured a single test client to be allowed through the filter – namely, the client with IPv4 address 192.168.1.192.

Comparing the Custom Rule to the Default

During the course of developing my custom firewall rule for the stcspserver.exe test application, I continually used the FwTool.exe “show” option to sanity check my work. It’s also interesting to use that tool to compare the custom rule to the rule that’s created by default. Note that the default rule is created in the following situation:

1.

2.

3.

4. Unblock button (or the Keep blocking button, which results in a different set of default rules).

I recommend using the sample application to cause the default Unblock rules to be created and to use the Firewall MMC snap-in review them. Not surprisingly, when this happens, all network traffic on any port and from any client can now be received by the designated application. This is perhaps a reasonable default behavior (based on the assumption that the user recognizes the application in question as trustworthy), given the need to compromise between usability and security in a consumer operating system. However, it further reinforces why the application developer should implement a much tighter rule configuration for installation (and un-installation).

Testing Each Rule Property

Once I had the stcpserver.exe application rule configured, I wanted to test each property of it to ensure that I was demonstrating a truly locked-down configuration. With that said, I realized that some of the properties would be easier to test than others. Furthermore, I assumed that there would be some properties that I’d like to test on an as-needed basis, and that testing these would require modifying my socket-related code on the client as well as the server. However, I didn’t really want to expose this in the command-line options (for example, the ability to send and receive UDP traffic).

To avoid that extra work, I used an existing network testing tool called NetCat. The current Windows version can be downloaded from http://www.vulnwatch.org/netcat/nc111nt.zip.

Application Name

First, as a warm-up for the testing phase of preparing this demo, I wanted to ensure that, based on my new firewall rule, only the designated server application name is allowed to listen on the open port. I started by configuring the server rule as discussed above.

>FwTool.exe add -n stcpserver -p 27015 -a 192.168.1.192

Success

Next, I ran NetCat (nc.exe) on the same server, with the appropriate command-line options to listen on the same port (type “nc.exe –h” for command-line help).

>nc.exe -l -p 27015

As a result, I immediately see the Windows Security Alert dialog box.

Figure 3 – Windows Security Alert

This is good – it indicates that, even though there are conditional “unblock” rules associated with the server application port, only binaries of the same name can open it. However, it’s important to mention that even a totally different application, if renamed to “stcpserver.exe,” can indeed open the port. I confirmed this by renaming “nc.exe” to “stcpserver.exe” and then re-running it with the same command-line options as above.

>del stcpserver.exe

>ren nc.exe stcpserver.exe

>stcpserver.exe -l -p 27015

Next, I ran the client application (shown below) from an allowed machine. In response, I saw “12345678” displayed by stcpserver/nc.exe on the server, indicating that the connection and data transmission was successful.

>stcpclient.exe testmachine6

Secure connection established to the server

Sent 8 bytes of data to the server

Therefore, it is indeed possible to bend the firewall rules a little more than you might like! Of course, if an attacker is actually able to run code in this manner on a server, there may be broader security problems to worry about. Still, I hope that Microsoft adds strong application identity to the firewall in a future release so that only a binary with a given cryptographic hash can match a given rule.

One final note about testing – I wanted to be sure to remove any firewall rules created by each test scenario, in order to ensure that downstream test results wouldn’t be affected. This can be accomplished via my FwTool.exe tool (shown below) or the Firewall MMC snap-in (see above). Also, after running this particular test case, don’t forget to rename nc.exe and stcpserver.exe, as appropriate!

>FwTool.exe delete -n nc

Success

>FwTool.exe delete -n stcpserver

Success

Protocol

In addition to verifying the behavior of the application identity filter I added, I wanted to confirm that the protocol filter was working as expected. In particular, only TCP traffic should be traversing the firewall based on my rule: no UDP traffic. This is easily confirmed using a variation of the test configuration discussed in the previous section.

First, I added a rule to allow NetCat the same network access that I granted the stcpserver demo application.

>FwTool.exe add -n nc -p 27015 -a 192.168.1.192

Success

During any testing effort, I recommend running a “positive” test case in conjunction with every “negative” test case. In other words, try the variation that should work, and then change a single variable to try the variation that shouldn’t work. This pattern is especially important when testing something as complex – and as critically important – as network security. To accomplish this in my current test scenario, I ran NetCat in TCP listen mode (its default) on the server as a positive test case.

>nc.exe -l -p 27015

Running NetCat in connect mode from the client confirms that the rule is allowing TCP traffic through:

>nc.exe testmachine6 27015

adsfasdfasdfasdf

How do I know that traffic is passing through the firewall? Easy – the “adsfasdfasdfasdf” string is echoed on the server (not shown). Finally, I re-ran the above two commands, but including the NetCat command-line option to send (and listen for) UDP packets instead of TCP. On the server:

>nc.exe -l -p 27015 –u

Then I ran the corresponding client-connect command:

>nc -u jwsecure-v6 27015

asdfasdfasdfasdf

I confirmed that the text I entered at the client was not echoed on the server. Finally, I cleaned up the created rules on the server to prepare for the next phase of testing.

>FwTool.exe delete -n nc

Success

>FwTool.exe delete -n stcpserver

Success

Client Address

Verifying the client address component of my demo rule is also straightforward. The optimal test scenario for the client address filter requires three machines: a server, an allowed client, and a denied client. However, there are also a variety of permutations that don’t require a second client.

The first step is to setup the server rule and confirm that the allowed client can successfully connect, as discussed at the beginning of the Testing section, above. Then, attempt to connect to the server from a different client (i.e. a different IP address).

>stcpclient.exe jwsecure-v6

WSAConnect returned error 10060

SecureTcpConnect returned error 10060

The error code above corresponds to “Connection timed out” (see http://msdn2.microsoft.com/en-us/library/ms740668.aspx). This confirms the negative test case as expected: a disallowed client address cannot connect to the server.

Conclusion

In general, the proper configuration and use of a software-based firewall is an important defense-in-depth measure. With the new Windows Firewall API, the Windows Vista release has made proper programmatic firewall configuration easier to accomplish. This is particularly true for conscientious ISVs who wish to make their customers’ lives easier by providing built-in firewall rule configuration with their network applications. The demo socket-based application discussed in this article is an example of this approach.

Acknowledgements

I am indebted to David Abzarian, Mahesh Mohan, Philippe Joubert, and Sarah Wahlert at Microsoft for their technical assistance in preparing this article.

About the Author

Dan Griffin is a software security consultant in Seattle, WA. He previously spent seven years at Microsoft on the Windows Security development team. Dan can be contacted at http://www.jwsecure.com.

this is draft content and is subject to change

Download sample, WFPSample.exe.

This is a Windows Filtering Platform sample project for the Windows Vista version of the Windows Driver Kit (WDK, also known as WinDDK 6000). The purpose of this sample code is to demonstrate the use of the Windows Filtering Platform provider contexts. In this sample, using a context allows information to be passed from a user mode component, which installs and configures a packet filter, to a kernel mode component that performs the actual filtering. The context information is simple in this case; it specifies a word replacement to be performed on the TCP stream.

  • To examine the user mode context creation code, see the call to FwpmProviderContextAdd0 in exe\medit.cpp!AppAddFilters

  • To examine the kernel mode context handling code, see the handler for FWPS_CALLOUT_NOTIFY_ADD_FILTER in sys\editor.c!StreamEditNotify.

This sample is based on the existing MSN Monitor sample, which is located at src\network\trans\msnmntr.

Running the Sample

Note

None of the filters, callouts, or sublayers in this demo are persistent.

  1. Build

    • Open a WinDDK 6000 (Windows Vista) build environment window.

    • Extract the source code included with this code sample package.

    • From the root directory of the source code, run build.exe. The root directory is the same directory where the dirs file is located.

  2. Install

    • Copy all of the binaries and msnmed.inf to a Windows Vista test computer.

    • On the Windows Vista test computer, right-click msnmed.inf and select Install.

  3. Run

    • Start the driver by running net start msnmed at a command prompt. Running net stop msnmed stops the driver.

    • Run medit.exe monitor to test the monitoring of content sent through MSN Messenger. You can use the TraceView tool to assist you with debugging. This tool is part of the WDK.

    • Run medit.exe word1 word2.

      Note

      In the current sample, word1 and word2 must be the same length. If you send text through MSN Messenger, word1 is replaced by word2. These filter words are implemented from user mode down to the kernel mode callout.

More Information and Errata

For more information, please see the MSDN online article which accompanies this sample. We will publish bugs and errata at http://www.jwsecure.com/dan/index.html. Please report new bugs by contacting JW Secure at http://www.jwsecure.com/contact.html.

this is draft content and is subject to change

Windows Vista heuristically detects installation programs and requests administrator credentials or approval from the administrator user in order to run with access privileges.

So applications called "setup.exe" and "install.exe" will prompt for administrator credentials (if running as standard user) or approval (if running as administrator). If you do not desire this behaviour then include a manifest with your application. See Catherine Heller's blog for information on how to embed a manifest.

For more information about UAC and installer detection see:

Here is a copy of my presentation from VS Connections Orlando 2007 yesterday, pdf.

, Installation Issues - Windows Vista

Note that you should download the Visual Studio 2005 SP1 and then right click on the file and choose "Run as administrator" - failure to do so may result in the slow running of the SP1 installer followed possibly by a silent setup failure.

Installation Issues – Windows Vista

Installation on Windows Vista requires elevated privileges:
If you are installing Visual Studio 2005 SP1 on Windows Vista, we recommend that you right-click the SP1 executable and then select Run as administrator. Alternatively, you can launch the executable from a privileged console window.
Setup dialog box fails to appear:

The verification that occurs under User Account Control (UAC) with all installations delays the appearance of the initial setup dialog box. Delays of more than one hour have been reported.

While we're at it, Visual Studio 2005 Service Pack 1 Update for Windows Vista also needs elevated privileges.

Technorati tags: ,

The .NET Compact Framework 1.0 SP3 Developer Redistributable is now available. The download is intended for developers with Visual Studio .NET 2003, it contains the SP3 CAB files:
Download

End user install is available here:
Download

"eLearning is an effective and efficient system of self-paced personal training, available over the Internet. Microsoft has made courses available in eLearning form to cover several of the important new technologies in Visual Studio 2005, including Connected Systems and Smart Clients, plus Windows Server 2003. More courses are planned for the near future."

http://msdn.microsoft.com/elearning/

http://go.microsoft.com/fwlink/?LinkId=46449