Bootstrapper - Security

In this article we will discuss security in the Bootstrapper.  Although setup.exe provides a great service of installing program prerequisites, how do you know you can trust it?  What if hackers attack a web server hosting redistributable packages?  Would every deployment then grab and install those compromised bits?

Rest assured that the Bootstrapper makes your installation experience as secure as possible.  Although we can’t verify that the intent of every package file is noble, we can verify that the package is precisely what the developer intended. 

If you trust the developers at Foobar.com, then you should trust their Bootstrapper to install the components their applications need.

Package verification overview
In order to verify the integrity of a package file the Bootstrapper keeps track of either a Hash or PublicKey value.  These are indicated by attributes in the Bootstrapper package manifest.

We will verify that the Hash or PublicKey value is what is expected at install-time so that once you, as the developer, create a Bootstraper [setup.exe] you can trust it to download exactly the prerequisites you specified.  If the Hash or PublicKey value of the download package doesn’t match that of what the Bootstrapper expects (the file on the developer’s machine) then the installation will fail.

We will provide code so you can obtain the Hash or PublicKey value for files later.

When packages are verified
The Bootstrapper actually verifies the integrity of the files it is deploying three times: at build, at download, and right before install.  This ensures the maximum protection as well as best experience to the end user.

Build time
At build time the Bootstrapper MSBuild task verifies the Hash / PublicKey values from the manifests against the package files on disk.  If there is anything that will cause an error at install-time (such as expected Hash verses the Hash of the file on disk) it will issue a build warning.

Download time
Once the Bootstrapper has been built and deployed out to ‘the wilds’ it will determine which packages need to be installed.  Once it has generated a list of files to obtain, it will download them from their HomeSites all across the internet.

Just after the Bootstrapper downloads a file it verifies its integrity.  This prevents you from downloading three 35MB malicious packages after you determine the first one is invalid. 

Install time
Just before we install a package we again verify its integrity.  This prevents attacks which plan to replace the package files in the TEMP directory before the Bootstrapper runs them.

With ‘triple checking’ the Bootstrapper ensures that the packages it downloads and installs are the same ones the developer intended to deploy. 

Other security measures
Although the Bootstrapper does everything it can to verify the packages downloaded / installed are valid, there is no guarantee to the end user that the setup.exe they are trusting is coming from a reputable source.  (That is you and not someone pretending to be you.)  The best way to secure your deployment is to Authenticode sign the bits you are deploying.

All ClickOnce deployments sign setup.exe with the same certificate as the application manifest.  For Setup Projects you can provide a .spc / .pvk pair to sign the output setup.exe and MSI as well.

Computing the Hash or PublicKey
Obtaining the file Hash or PublicKey is a simple task, once you know how.  The following code is from an internal tool uniquely named WindowsApplication21:

Option

Strict On
Option Explicit On

Imports System.Security.Cryptography

Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs)
                                      Handles btnOpenFile.Click

Dim ofd As New OpenFileDialog()

      If ofd.ShowDialog() = Windows.Forms.DialogResult.OK Then

         Dim fi As New System.IO.FileInfo(ofd.FileName)
Dim s As System.IO.Stream = fi.OpenRead()

         ' Get the file Hash
Dim sha As New SHA1Managed()
Me.tbHash.Text = ByteArrayToString(sha.ComputeHash(s))
         s.Close()

' Get the file PublicKey
         Try
Dim cert As New X509Certificates.X509Certificate(ofd.FileName)

Me.tbPublicKey.Text = cert.GetPublicKeyString()
Catch ex As Exception
            ' Ignore, this usually indicates the file isn't signed
         End Try

      End If
   
      Refresh()
   End Sub

' Convert a byte array to a hex string
   Private Function ByteArrayToString(ByVal byteArray As Byte()) As String
      If byteArray Is Nothing Then Return ""

      Dim output As New System.Text.StringBuilder(byteArray.Length)
For Each byteValue As Byte In byteArray
output.Append(byteValue.ToString("X02"))
      Next

Return output.ToString()
End Function
End Class

Disclaimer
The information provided here is subject to change without notice.  Also, the code snippet could hork, destroy, or cause your computer to actually burst into flames!  It offers absolutely no warranty and is provided ‘as is’.  Use at your own discretion.