Wednesday, July 30, 2014

Why Schannel EventID 36888 / 36874 Occurs and How to Fix It



Having trouble talking to your webserver? Seeing the aforementioned errors? Are you hungry?

I can fix two of those. I ran into this error at a large, highly distributed client site. Because of the nature of the problem (sporadic) it took longer to solve than I would have liked. Hopefully this article will save you that time.


What Components are Involved?

This error involves two sides: a "client" and a server. Client is in quotes because it can be, and often is, an application consuming a web service or similar. On the server side this problem generally occurs on Windows 2008 or newer. The "client" can be any platform.

What Errors Again?


Generally, but not always, these errors are manifested into following events:
  • System Log, Schannel source, EventID 36888
  • System Log, Schannel source, EventID 36874

These errors can occur on either side, provided obviously that side is Windows. What errors you receive on the other side depend entirely on the platform.

What is Happening?

At a high level, the client and server are failing to agree on a way to talk to each other securely. To communicate securely, the server and client must agree on a methodology to communicate involving 4 main components. Those are:
  • How to authenticate each other (Key Exchange)
  • How to encrypt data to be exchanged (Encryption Cipher)
  • How to verify the message hasn't been tampered with (Message Authentication Code)
  • How to determine random numbers for seeding keys (Pseudorandom Function)

The client and server must agree to the same implementation of each of these items. Bundled together, these are referred to as a cipher suite

The client and server each have preferences as to which portions of the cipher suite hold which priority. Based on this prioritization, a set of supported cipher suites is compiled and proposed at the beginning of any SSL/TLS connection. The client first proposes what it would like, then the server compares the client list to its own list and selects the first matching suite.

So therein lies the problem: Your server doesn't like any of the proposals from the client. 

Why?

This is why I decided to write this article. While there are several hits on the internet regarding this problem, I have yet to see one that nails it. Initially (and originally published in this article) I suspected the problem was due to an incorrect cryptographic service provider but thanks to some insights from one of my colleagues I took another look. Turns out that due to the nature of this problem it can appear sporadically and be difficult to troubleshoot. If you're experiencing this problem the following may be true of your environment:

If those things aren't true, don't worry because here are the details: If your CSR is requesting a certificate that is valid for signing only, rather than signing and encryption, and your CA has a policy that allows for encryption even when the request was signing only, then you will likely see this problem... sometimes. Clearly a certificate requested for signature only shouldn't work at all when used for encryption, but if your CA overrides the request to allow for encryption that will create a situation where encryption will work, but only under circumstances when the client supports a couple specific protocol suites. Identifying certificates causing this problem is complicated; since the CA overrode the We'll cover the specifics further in the next two sections...

Detecting The Problem

Feel free to skip this section if you want to jump to the fix. Detection can be pretty easy using tools like Wireshark. Fire up the tool on either the client or server with the proper capture filters to reduce noise, and then attempt the failing connection. You will see only a handful of packets (5 or so) as the rejection happens pretty quickly. To see the detail appropriately, you'll need to tell Wireshark this is SSL/TLS by right clicking->decode as->SSL.

If a protocol negotiation is the issue, you'll see the connection reset by the server immediately after the client suggests a list of cipher suites. This packet from the client will have the info of "client hello" followed immediately with a TCP RST (reset) from the server.

If you drill into the details of the "client hello" packet you will be able to see the suites the client is proposing.

You can then attempt a successful TLS connection if you are able to produce one (if not just jump to the fix and try it) using the same methodology. I found that while using the affected cert type listed above, my server only supported TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA  and TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, clearly a very limited subset. 

The Fix

To remediate this issue you'll need to make sure that  certificate ordered is for the correct purpose. Rather than recreate that article I'll direct you to my favorite one here, however note that the [strings],[Extensions],and [RequestAttributes] sections may not be needed depending on your situation. The main takeaway from that article is that at the very least the KeySpec and KeyUsage settings need to be specified (see link under references for more info).  Request, retrieve, and install this certificate.

You can use any other method you would like to obtain a certificate (perhaps you do), but it's critical to ensure your request has the correct parameters including the certificate usage. If you are using Windows PKI with AD integrated templates, you can "hard code" this in the templates if you like.

If this fix didn't work for you, wait for the "Wait There's More" section because it's likely due to a misconfigured set of cipher suites. Speaking of that...

Wait There's More

As a security best practice, you should also control (restrict) your available cipher suites on Windows/IIS. This is pretty easy to do; it can be done via Group Policy for large sets of servers and one-by-one with registry settings or better yet with this easy tool from Nartac. For more guidance check out these three links.

Thanks for reading and feel free to add your own experience below!

References

Microsoft Support: How to Determine the Cipher Suite for the Server and Client

Microsoft Support: How to restrict the use of certain cryptographic algorithms and protocols in Schannel.dll

MSDN: Cipher Suites in Schannel

Technet: Certreq.exe syntax

Sunday, July 6, 2014

Setup Your Own Chocoloatey/NuGet Repository

In this article we'll examine setting up a NuGet/Chocolatey repository in your enterprise to distribute software. This will allow you to easily distribute development and software packages throughout your network.

NuGet? I don't need any more candy.

NuGet started life NuPack (not to be confused with NuPack), an open source solution for managing .NET packages. Since then it has evolved into a mature platform with numerous interfaces including a Visual Studio plugin, command line, and Mono support. Chocolatey and PowerShellGet are built on that framework. Speaking of Chocolate...

Chocolatey? I told you already, no more candy.

Where NuGet was meant for .NET packages, Chocolatey, which is built on the same infrastructure, is meant for machine (Windows) packages. Think of it like apt or yum for windows. PowerShell has also already shipped a preview of PowerShell OneGet which can use Chocolatey repositories.

But There are Already Repositories for These and I'm Hungry! Why Would I Make My Own?

Yup! There are great public repositories for Chocolatey and NuGet, but those are geared at freely available public software that wouldn't be built for an explicit purpose. By hosting your own you can host custom .NET packages specific to your business unit or even package commercially available software for distribution with Chocolatey provided your licensing is up to snuff.


Hosting Options


There are several options to get going that vary in terms of hosting location, ease of installation, and scalability. Some of the more popular options include:
  • NuGet Server : A basic server that runs on-premise and is easy to setup. Doesn't have granular security features and will only scale so far before it slows down.
  • NuGet Gallery: More complex NuGet server package that includes advanced security features and will scale for larger implementations (this is what the main public NuGet repo uses). 
  • MyGet: A commercial NuGet repo service hosted in Azure. Has a limited free tier and reasonably priced paid tiers. Worth consideration if you don't want to host your own infrastructure. 

The assumption with this article is that you're hosting your first NuGet/Chocolately repo for the purposes of your enterprise or team use. Since the NuGet server includes most needed functionality for that purpose and can be replaced with the NuGet Gallery as you grow, we'll set up a NuGet Server(the first option) in this article.

Let's Get Started!

Assumptions

  • We'll be setting up on a Windows Server 2012 R2. This will work on Windows Server 2008 and up. I'm assuming you have one set up and ready to go.
  • (Updated, see note below) You will need Visual Studio Express 2010/2012 or Visual Studio Community 2013 or newer on your workstation. (Preferably not on the server)
  • You will need Admin rights on both the server and your workstation.
  • In enterprise environments you often have to make due with the resources you have available, so we'll be setting up the repo as a virtual application in IIS rather than its own site so that it can share port 80 for the sake of simplicity.

IIS Setup on Server

We'll walk through installing the minimum IIS requirements to run the NuGet Server package. Everything here could be very easily done with PowerShell but we'll use the GUI to make for a more visual tutorial.

  1. On the server where you will host the application, start the "Add Roles and Features Wizard"
  2. Click "Next" until you advance to the "Server Roles" section. If you're executing remotely make sure you select the correct server.
  3. Of the Roles listed, select "Web Server (IIS)" and select "Add Features" when prompted. Click "Next". 


  4. On the "Features" page, expand ".NET Framework 4.5 Features" and ensure ".NET Framework 4.5" and "ASP.NET 4.5" are checked. Click "Next".


  5. Click "Next" to advance to the "Role Services" section under "Web Server Role (IIS)" and select the following (only the most granular required, not the headings):
    • Web Server
      • Common HTTP Features
        • Default Document
        • Static Content
      • Health and Diagnostics
        • HTTP Logging
      • Performance
        • Static Content Compression
      • Security
        • Request Filtering
      • Application Development
        • .NET Extensibility 4.5
        • ASP.NET 4.5
        • ISAPI Extensions
        • ISAPI Filters
    • Management Tools
      • IIS Management Console


  6. Click "Next" and then click "Install".
  7. You shouldn't need to reboot, but check the installation status and do so if requested.

IIS Setup on Server

Now we'll set up the site that the NuGet Server will be served from. As mentioned earlier, I will walk you through setting it up as a virtual application off of the default web site. This configuration would allow you to share port 80 with an existing site as well as show you how to configure this application below the root, which does need a bit of special consideration worth mentioning.
  1. Create the directory structure for your site. I always put my IIS sites on a non-system drive with the permissions locked down. In this example, I'll be using D:\Sites\NuGetRepo .
  2. Create the directory for the NuGet/Chocolately package repo. We'll configure this below. This directory uses a different permissions structure and could potentially be shared out over your LAN, so it may be beneficial to place this separate from the site. In my example I'll be using D:\NuGetRepo .
  3. (Optional/Best Practice) At the D:\Sites and D:\NuGetRepo levels disable inheritance ensure only Administrators and SYSTEM have write access. Do not allow any other access at this time, we'll get to that below.
  4. On the server to host NuGet Server, open the IIS management tool.
  5. Right click the Default Web Site (note this could be any web site) and select "Add Application..." (A virtual directory will not work!)


  6. Set the alias to "NuGet", leave the "Application Pool" on "DefaultApplicationPool" (again, you could change this if desired) and set the physical path to what you created for the site. For our example we're using "D:\Sites\NuGetRepo" . 


  7. The default out-of-box settings should work for the site, but in case the Default Web Site settings have been changed you may want to refresh your view and ensure IIS authentication is set to "Anonymous". If desired, change the logging location as well (D:\logfiles\IIS\NuGetRepo for example).

Setting File System Permissions on IIS Server

For clients to access the site and repo successfully we need to set file system level permissions. If you have used different directory names above substitute them here accordingly.

Note: We're assuming you have administrative access to this server from your Workstation as well to deploy the code in the steps below. If not, you'll need to grant whoever will be deploying the site access to the site folder. If you are admin, don't worry about it.

  1. The directory containing the website needs to be read by the AppPool account and the Anon user account. Right click D:\Sites\NuGetRepo and select "Properties".
  2. Click "Security", "Edit", and then "Add". Change the "Location" to the local system name.
  3. Give the default web site application pool virtual service account and anonymous account permissions by typing "IIS APPPOOL\DefaultAppPool;IUSR", clicking "Check Names" and then "OK". Again, if you have elected to use a different site/pool/acct you will need to take that into account. This should resolve to two accounts, "DefaultAppPool" and IUSR".


  4. Give each of the added users "Read & Execute", "List folder contents", and "Read" permissions and then click "OK".


  5. The directory containing the actual repo only needs to be read by the AppPool account. Right click D:\NuGetRepo and select "Properties".
  6. Click "Security", "Edit", and then "Add". Change the "Location" to the local system name.
  7. Give the default web site application pool virtual service account permissions by typing "IIS APPPOOL\DefaultAppPool", clicking "Check Names" and then "OK". Again, if you have elected to use a different site/pool/acct you will need to take that into account. This should resolve to one account, "DefaultAppPool".
  8. Grant it "Read & Execute", "List folder contents", and "Read" permissions and then click "OK".


NuGet Server Config on Workstation

Now we'll grab the NuGet Server package and configure it accordingly. Note some of these options will vary slightly depending on which version of Visual Studio you are using. I'm using 2012 Premium but everything is possible in 2010 Express and up. Edit: As pointed out by Nik below it looks as if Microsoft changed this starting in 2013. For 2013 and higher you'll need the community edition.

Note: We are assuming your IIS server is accessible to you and has file sharing turned on to push the site. If you are unable to get to the filesystem of the server from this machine you will need to use a different deployment mechanism when we get to that step.

  1. On your workstation, open Visual Studio and start a new Project by selecting "File"->"New"->"Project"


  2. Navigate to "Installed"->"Templates"->"Visual C#"->"Web" and select "ASP.NET Empty Web Application"


  3. Right click on your newly created application under the solution and select "Manage NuGet Packages"


  4. Assuming the defaults of the nuget.org feed and "Stable Only" are selected, type "nuget.server" in the search box and hit Enter
  5. Select the "NuGet.Server" package and click "Install". This will install the NuGet server package and any dependencies. Accept license agreements associated with the other packages to continue and then close the package management window.


  6. The only thing we need to customize is the web.config  file for our installation. In the Solution Explorer click "Web.config" under the web application. Note: This file is also where you can control API Key behavior, but that is outside the scope of this article.
  7. Look for the add key="packagesPath" entry in the web.config file under the "<appSettings>" heading. We need to set this to the location of our repository. Change <add key="packagesPath" value=""/> to <add key="packagesPath" value="D:\NuGetRepo"/> (or other directory if appropriate). Note that there is no trailing slash. Save your project.


  8. Now we need to publish. Click "Build"->"Publish WebApplication..."


  9. If you already have a working publishing profile for the web server, select it and skip to step 12. Otherwise, select <new profile> from the drop-down box, enter a name, and click "OK". 


  10. Change "Publish method" to "File System" and enter the full path to the web server site location, I.E. "\\<server>\d$\sites\NuGetRepo\" . Click "Next".
  11. Accept the default publishing settings and click "Next". 
  12. Review the settings and click "Publish". 
  13. Review the Output window to ensure there weren't any errors.


  14. Test your NuGet Server by navigating to http://<servername>/NuGet/ . If you encounter errors be sure to browse to it locally on the server to get the full error information.


That's it! Now all you need to do is configure the source in your clients, make packages, and enjoy! For instructions on those steps see below, and stay tuned for more. Thanks for reading!

Creating NuGet/Chocolatey Packages

Chocolatey.org : all things Chocolatey!
Chocolatey Docs: Create Packages Quick Start
NuGet Docs: Nuspec Reference
Chocolatey Docs: Chocolately Templates
NuGet Docs: Creating and Publishing a Package
Scott Hanselman: Creating a NuGet Package in 7 Easy Steps!
Chocolatey Docs: Creating Chocolatey Packages
Hong Xu: Create and Publish Chocolatey Packages
NuGet Docs: Configuration File and Source Code Transformations

Configuring Sources

Chocolatey Docs: Source command
NuGet Docs: Visual Studio Package Sources

References!

NuGet Docs: Hosting Your Own Feeds
Scott Hanselman: Is the Windows User Ready for Apt-Get?
MBrownNYC: Create Your Own NuGet Server to Serve Packages for Chocolatey
NuGet Docs: An Overview of the NuGet Ecosystem