Saturday, January 30, 2010

How To: Set Up BitLocker Full Disk Encryption + Pre-Boot Pin in Windows 7 Ultimate

Ok, this goes in the "and Beyond..." category because this post is not specific to .NET, but about setting up full disk encryption using a product by Microsoft named BitLocker. BitLocker is included is some of the premium Windows Vista and Windows 7 editions; specifically this post speaks of how to set up full disk encryption on Windows 7 Ultimate Edition.

There are several reasons for using full disk encryption; sometimes it is a requirement of the company you work for, or maybe you have sensitive information that needs to be secured in the event of your computer being lost or stolen. While traditionally you may think of using BitLocker just for laptops because of their portability which brings an increased risk of loss or theft, this could be done on a desktop with the appropriate hardware required as well.

I will preface these directions with some cautions and warnings. The process although not rocket science, is a series of steps that must be followed quite closely with no variations. I myself have had some unsuccessful attempts at setting up the encryption, which caused an OS failure, and the need to reformat and reinstall the OS again. That being said... "BACK UP EVERYTHING IMPORTANT BEFORE SETTING UP ENCRYPTION!" Ideally, you would do this initially upon getting a new laptop with Windows 7, or after doing a fresh install. That way if you run into any major issues, you can re-image the machine to its default configuration and start over again. I do believe that encryption overall makes the hard drive a tad bit more volatile, so regardless of the success of encrypting your disk, I recommend backing up important files from time to time after encryption is complete.

There are a few prerequisites to using BitLocker and full disk encryption. 1st, you need to have Administrative rights on the machine. The 2nd I already spoke of and that is needing Windows 7 Ultimate. The 3rd is a device that is imbedded in the laptop or machine called a TPM or "Trusted Platform Module". The TPM is responsible for generating and storing a keyset used for the drive encryption and for integrity checks of the system boot files. This results in securing the system volume with encryption and integrity checking the system boot files to ensure that nothing has been tampered with and the system drive is located in the original computer. Only then is decryption preformed. While there are software only solution for full drive encryption, they are more susceptible to hackers than BitLocker used with a TPM. Microsoft has published a wealth of detail on the underlying workings of BitLocker and the TPM, so I will not repeat it here. If you are interested, check out either of the following sites:

BitLocker Drive Encryption Team Blog

TechNet: BitLocker Drive Encryption

Alright now to the meat and potatoes of this project. Remember, try to follow each step as closely as possible without deviation for the nest results.

Step # 1: Backup all important files. Let me say again... Back up all important files. Just in case you have any issue with setting up BitLocker, you will not have lost all of your important data.

Step # 2: Update the BIOS for your machine to the most up to date version. Each motherboard or machine is going to have their own website for instructions and downloading and updating the BIOS. For example Dell has a site for its updates, ASUS has a site for their motherboard updates, etc. Oh, and if you are reading this and not sure what the BIOS is... I recommend to halt this procedure and not continue. Just my advice.

Step # 3: Log into Windows after the BIOS is updated and go to the following: Start -> Control Panel -> BitLocker Encryption. Find your Hard Drive and select "Turn BitLocker On". It should probably not work giving you the message below stating a TPM could not be found. If for some reason the BitLocker process begins because your TPM was already configured, should cancel the process and do the 2nd part of Step # 4: Configuring the boot sequence from the BIOS.

Step # 4: Enter the BIOS on boot and Enable the TPM and configure the boot sequence. 1st, enter the BIOS and find the TPM settings. They are probably under a 'Security' heading or something similar. All BIOS menus are different, so I don’t have the specific directions for each one, but navigate around until you find it. Once you do, select the option to enable it. 2nd, reconfigure the boot sequence. Make sure that any option for USB or Flash drives boot AFTER the Hard Drive. This sort of undocumented step caused me a lot of failed encryptions in later steps. The reason is that upon doing the BitLocker System Check, the system reboots and checks to make sure the generated keys placed on your USB Flash Drive actually work properly, prior to actually doing the encryption. Well if the USB is ordered to boot prior to the hard drive, the machine thinks you are using the USB as a boot device and forfeits the BitLocker check. You need to have the hard drive boot prior to the USB drive. No worries, though, if you ever need to boot from a DVD or flash, just go back in and switch the order to do whatever processing you need and then switch it back. Save your changes and exit the BIOS.

Step # 5: Set up BitLocker and the TPM. Log all the way back into Windows (do not shut down in-between) and go back to the BitLocker Encryption option in the Control Panel. Press "Turn On BitLocker" again. This time the BitLocker process will recognize a TPM enabled and being the process. You should see screens such as the following below:

Press 'Next' to begin BitLocker preparations:

Press 'Next' to begin the allocation of space for BitLocker:

Press 'Restart Now' and allow the machine to reboot as displayed below:

Upon logging back into Windows, BitLocker will continue the process automatically, so do not attempt to open anything else. You will see the screen below, and to continue the process press 'Next':

Upon completing the steps above, you will be prompted to reboot the computer so that the TPM can be configures. Press 'Restart' as directed. Upon rebooting, you will see a basic MS-DOS old school looking screen informing you that the TPM has been modified and do you want to allow the modification. Allow the modification and follow the directions to press the appropriate button. In my case I selected the 'Modify' (not the 'Ignore') so that the TPM configuration could be modified. Upon completion, the machine will reboot. Log all the way back into Windows. The BitLocker process will proceed automatically again. You should see a screen like below:

One the TPM hardware has been configured you will see a screen like below; press 'Next' to continue the process:

At this point you will be prompted to save off the recovery keys. These are the keys that are stored in the TPM, and are only needed in the event of system tampering or breech. I recommend doing all (3) options, and storing the keys to a USB drive, printing them off, and saving them off to a location OTHER THAN the system drive (secure network share, etc.). Obviously I should not need to explains too much here that the keys regardless of type (paper, USB, file) need to be locked away. Don’t leave the USB on the desk next to the laptop, or the paper with the keys folded under the machine. That is like leaving the keys to the car in the door lock. Continuing each option in the screen below to save off the keys:

Step # 6: Run the BitLocker Check (USB with keys saved from Step # 5 required for this step). After saving the keys from above, press 'Next. You will see the screen below asking if you want to run the BitLocker check. While not required, I recommend doing it. You don't want to encrypt the drive until you have tested that the generated keys actually work. Check the box to run the BitLocker check and make sure that the USB drive IS INSERTED in the machine. Press 'Next' and the following reminder and reboot screens will be displayed:

Step # 7: Full drive encryption. Upon a successful reboot and USB keys check, the BitLocker process will automatically being the encryption process of the system volume. This will take several hours depending on the size of the drive, but you can continue to work in the background if needed. However, do not reboot or shut down during the encryption process. You can lock your machine if needed. The encryption dialog (shown below) will display the progress.

Step # 8: Configure the machine policy to require a pre boot PIN + TPM (Optional). Once the encryption is complete, you are technically done. The drive is encrypted and secure. You will notice upon reboot you are never prompted for the keys or a password. That's normal. The TPM has the keys, and if there was any breech or integrity failure, you would be prompted for the keys. Otherwise the authentication occurs in the background and is seamless.

However, to strengthen your security you may want to configure a pre boot PIN that works separately but in conjunction with the TPM. To accomplish this, follow Step # 8 and Step # 9 and Step # 10.

We need to open the Group Policy editor for the machine. Goto Start -> and type in gpedit.msc and press 'Enter'. Then Goto: Local Computer Policy > Computer Configuration > Administrative Templates > Windows Components > BitLocker Drive Encryption > Operating System Drives and right click the option "Require additional authentication at startup" and select "Edit". The screen is displayed below:

Select "Enabled" and then select "Require startup PIN with TPM" under the "Configure TPM startup PIN:" dropdown. Click "Apply, "OK" then close the dialog and Group Policy editor. This now allows us to configure the pre boot PIN from the command prompt.

Step # 9: Goto Start and type in cmd but do NOT press enter. Once the cmd application displays in the start menu, right click it and state "Run as Administrator". Click "Yes" on any security dialogs that may appear. To configure the pin we need to use the manage-bde.exe tool. To configure the PIN, enter the following and then press 'Enter':

manage-bde -protectors -add %systemdrive% -tpmandpin

You will be prompted to enter a PIN. (Note: I did notice if you still have the USB with the keys inserted into the machine, this process does not work - the command prompt never asks you to enter the PIN; make sure to remove it before doing this process). The PIN by default can only be numeric. There is an option in the group policy editor from Step # 7, to allow complex PINs for this process, but wars not all systems support it. Since you may not find that out until reboot, and not be able to log back in, I suggest just using a numeric PIN. You will be prompted to enter it twice, and upon success, see a screen like the one below:

Step # 10: Reboot and test the PIN. Upon rebooting, after the quick flash of your system manufacture screen, you should receive an old MS-DOS style screen prompting you for your PIN. It tells you the function keys can be used to represent numbers, but I always just use the keypad and it works fine. If needed, the option is there. Upon entering the correct PIN the machine will continue booting into Windows. One note on the pre-boot PIN: I have found that if you have your USB containing the keys inserted upon boot, it assumes you are validated and skips the prompting of the PIN. Since your USB drive should be locked away, you will be prompted for the PIN, but again, another nice option if needed.

And that is it! Hopefully your encryption process went well and you are complete at this point. I have done this process on 7 different machines with success, so I know it works when followed as directed. Your drive will now be secure with BitLocker.

Tuesday, January 26, 2010

Add Missing Build Configuration DropDown to VS.NET

If you are like me, then you probably enjoy the convenience of the Build Configuration menu inside of Visual Studio.NET. This is the menu that contains the "Debug" and "Release" modes for project deployment configuration. Well when I build a new machine or re-install VS.NET, I notice that the build dropdown is not always displayed by default. So here are a few simple steps to get the menu back being displayed.

1. Goto the View -> Toolbars-> Customize menu in VS.NET. Select the 'Build' category on the left side, and scroll down to "Solution Configuration". Click and drag it to the location on your VS.NET menu where you would like it to be located. At this point you probably notice the dropdown is added, but is greyed out, and might not even have any option shown similar to the picture below (Step # 2 fixes this):

2. To now enable the menu goto the Tools -> Options menu. On the left side expand the "Projects and Solutions" section and select "General". Then on the right hand side, check the box that states "Show advanced build configurations".

That's it! You should now have an enabled build configuration menu in VS.NET.

Sunday, January 10, 2010

How To: Create an ASP.NET style Windows Authentication Policy for WCF Services

For those of you that program on a Windows Domain probably in a corporate environment, you were probably well familiar with using Windows Authentication in .asmx web services to restrict or permit users access. Do you remember how easy it was in a .asmx web service to allow only a specific user or group? Take a look below from the only setting needed in the web.config file associated with the web service:

That was it! Now let's not start off on the wrong foot here or give the wrong impression. I am a huge advocate of WCF over .asmx services and definently think it is the way to go. With WCF having such a broad use capability and granular level of control and functionality, came the loss of some of the bundled up functionality that was specific to IIS hosted .asmx web services. This is not a bad thing at all.

However, those of us that work with WCF came to quickly realize that with just a small configuration you could easily configure WCF to only allow Windows Authenticated users to access the service, but that was it. There was no clean direct way to restrict the Windows Users or Groups in a 'blanket' fashion as was the case with .asmx web services and the configuration shown above. Not even setting the WCF service to ASPCompatibilityMode could directly accomplish the configuration above.

So there are (2) main ways to get around this issue. The 1st method to get around this would be to define PrincipalPermission attributes on every method to define its security requirements. This means hardcoding the security requirements, and is not as flexible as info that comes from a .config file. In some cases this method by method style of security may be desired, but often our services are an all or nothing style of access.

The 2nd solution, and the focus of this article, is to intercept the authorization calls to your WCF service and examine the identity of the user making the call to determine if they are authorized. We as developers are provided the ability to extend the 'ServiceAuthorizationManager' class and override the 'CheckAccessCore()' method to define our own custom authorization policy for the service. It is within this method that you can scrutinize the individual roles, groups, or users authorized by extracting the WindowsIdentity of the context, and then either permitting or rejecting access based on your requirements. Within here you could pull the authorized roles, users, or groups from the WCF .config file.

To get right to the code, below I have provided the implementation of the overriden 'CheckAccessCore()' method. The robust comments within should detail well what each step is doing:

Imports System.Configuration
Imports System.Security.Principal
Imports System.IdentityModel.Tokens

''' The Identity Model infrastructure in Windows Communication Foundation (WCF) supports an extensible claims-based authorization
''' model. Claims are extracted from tokens and optionally processed by custom authorization policies and then placed into an
''' AuthorizationContext. An authorization manager examines the claims in the AuthorizationContext to make authorization decisions.
''' By default, authorization decisions are made by the ServiceAuthorizationManager class; however these decisions can be
''' overridden by creating a custom authorization manager. To create a custom authorization manager, create a class that derives
''' from ServiceAuthorizationManager (this class) and implement CheckAccessCore method (done in this class). Authorization
''' decisions are made in the CheckAccessCore method, which returns 'true' when access is granted and 'false' when access is denied.
''' In our case, we are examining the Windows Identity of the current user's context and checking it against some predefined
''' permitted users and roles from the AppSettings section of the associated services' .config file.

''' Because of performance issues, if possible you should design your application
''' so that the authorization decision does NOT require access to the message body.
''' Registration of the custom authorization manager for a service can be done in code or configuration.

Public Class CustomAuthorizationManager
Inherits ServiceAuthorizationManager

Protected Overloads Overrides Function CheckAccessCore(ByVal operationContext As OperationContext) As Boolean

'For mex support (starting WCF service, etc.)
'NOTE: Other than for service startup this will NOT be true because the WCF
'configuration dictates that WindowsCredentials must be sent and Anonymous users
'are NOT allowed.
If operationContext.ServiceSecurityContext.IsAnonymous Then
Return True
End If

'If Windows Authentication has been defined in the binding and either of the (2)
'predefined AppSettings are populated, proceed to authorize current user/group against allowed users or groups.
If (ConfigurationManager.AppSettings("AuthorizedGroups") IsNot Nothing) OrElse _
(ConfigurationManager.AppSettings("AuthorizedUsers") IsNot Nothing) Then

Dim IdentityIsAuthorized As Boolean = False

'Extract the identity token of the current context user making the call to this service
Dim Identity As WindowsIdentity = operationContext.ServiceSecurityContext.WindowsIdentity
'Create a WindowsPrincipal object from the identity to view the user's name and group information
Dim Principal As New WindowsPrincipal(Identity)

'Prior to proceeding, throw an exception if the user has not been authenticated at all
'if the 'AppSettings' section are populated indicating the Windows Authentication should be checked.
If Identity.IsAuthenticated = False Then
Throw New SecurityTokenValidationException("Windows authenticated user is required to call this service.")
End If

'Define (2) string arrays that will hold the values of users and groups with permitted access from the .config file:
Dim AuthorizedGroups As String() = Nothing
Dim AuthorizedUsers As String() = Nothing

'Procced to check the AuthorizedGroups if defined, against the current user's Groups
If ConfigurationManager.AppSettings("AuthorizedGroups") IsNot Nothing Then
'The values in the .config are separated by a comma, so split them out to iterate through below:
AuthorizedGroups = ConfigurationManager.AppSettings("AuthorizedGroups").ToString().Split(",")

'Iterate through all of the permitted groups from the .config file:
For Each Group As String In AuthorizedGroups
'If the user exists in one of the permitted Groups from the AppSettings "AuthorizedGroups" values,
'then set value indicating that the user Is Authorized.
If Principal.IsInRole(Group) Then IdentityIsAuthorized = True

End If

'Procced to check the AuthorizedUsers if defined, against the current user's name
If ConfigurationManager.AppSettings("AuthorizedUsers") IsNot Nothing Then
'The values in the .config are separated by a comma, so split them out to iterate through below:
AuthorizedUsers = ConfigurationManager.AppSettings("AuthorizedUsers").ToString().Split(",")

'Iterate through all of the permitted users from the .config file:
For Each User As String In AuthorizedUsers
'If the user exists as one of the permitted users from the AppSettings "AuthorizedUsers" values,
'then set value indicating that the user Is Authorized.
If Identity.Name.ToLower() = User.ToLower() Then IdentityIsAuthorized = True

End If

'Return the boolena indicating if the user is authorized to proceed:
Return IdentityIsAuthorized

'Call the base class implementation of the CheckAccessCore method to make authorization decisions
'since no defined users or groups were defined in this service's .config file.
Return MyBase.CheckAccessCore(operationContext)

End If

End Function

End Class

Notice from the code above, that we have defined (2) key values which of at least (1) must exist for the code above to work. The appSettings sections are named: AuthorizedGroups and AuthorizedUsers. Below is a sample configuration using both of these values:

In addition to the overridden method and appSettings values, we must configure the WCF behavior for our service to indicate the Service Authorization Manager name as displayed below:

You also need to specify within the binding that the clientCrendentals are of type 'Windows'. To show the node fully, I have included the full 'Security' node in which I was using Transport security, but this can be configured for your needs and is not specific to this procedure:

That will be everything you need to 'intercept' the authorization calls to your WCF service and scrutinize the users permitted. Want to see it work? The easiest way to test this is to build a WCF Service and add the code from this article into or above the Service1 default class that is generated from VS.NET. Once your WCF will compile, start the service locally (no need to install) and place a breakpoint on the 1st line in the 'CheckAccessCore()' method. You will be able to tell if the WCF service starts because service client dialog window will display with the methods in your test service. If you leave the default generated code in the service, it exposes (2) methods: GetData() and GetDateUsingDataContract().

To test this all out I created a test ASP.NET web application and consumed the WCF service. Make sure the service is running when attempting to consume it. You can find the link to consume your service in the WCF Service dialog window. For my test project, mine happend to be net.tcp://localhost:8731/Design_Time_Addresses/WcfServiceWindowsSecurityTest/Service1/mex

Once consumed, I added a little bit of code to test as shown below:

Dim wcfSecurityTest As New WindowsSecurityService.Service1Client
'Obviously NEVER hardcode credentials like the example ONLY below
wcfSecurityTest.ClientCredentials.Windows.ClientCredential = New System.Net.NetworkCredential("jsmith", "testpassword", "MyCompany")
'Upon making the call below, the WCF will call the overriden CheckAccessCore() method to allow or reject authorization:

When calling the 'GetData()' method above and having a break point in the running WCF service, you will notice the WCF service hit the breakpoint in our 'CheckAccessCore()' method (pretty cool). From here you can debug the method and see how it works.

Hopefully this gets you back to enabling whole application Windows Authentication on your WCF services!