Wednesday, July 30, 2014

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 thesethreelinks.

Sunday, July 6, 2014

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.

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.

On the server where you will host the application, start the "Add
Roles and Features Wizard"

Click "Next" until you advance to the "Server
Roles" section. If you're executing remotely make sure you
select the correct server.

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

Click "Next" and then click "Install".

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.

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 .

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 .

(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.

On the server to host NuGet Server, open the IIS management
tool.

Right click the Default Web Site (note this could be
any web site) and select "Add Application..." (A
virtual directory will not work!)

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" .

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.

The directory containing the website needs to be read by the AppPool
account and the Anon user account. Right clickD:\Sites\NuGetRepo
and select "Properties".

Click "Security", "Edit", and then "Add".
Change the "Location" to the local system name.

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".

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

The directory containing the actual repo only needs to be read by the
AppPool account. Right clickD:\NuGetRepo
and select "Properties".

Click "Security", "Edit", and then "Add".
Change the "Location" to the local system
name.

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".

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.

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

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

Assuming the defaults of the nuget.org feed and "Stable Only" are
selected, type "nuget.server" in the search box and hit
Enter.

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.

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.

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.

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

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".

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".

Accept the default publishing settings and click "Next".

Review the settings and click "Publish".

Review the Output window to ensure there weren't any
errors.

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!