How do I securely configure a CI server to digitally sign binaries? - continuous-integration

There are many sites that explain how to run signtool.exe on a .pfx certificate file, which boil down to:
signtool.exe sign /f mycert.pfx /p mypassword /t http://timestamp.server.com \
/d "My description" file1.exe file2.exe
I have a continuous integration CI process setup (using TeamCity) which like most CI processes, does everything: checks out source, compiles, signs all .exes, packages into an installer, and signs the installer .exe. There are currently 3 build agents, running identical VMs, and any of them can run this process.
Insecure implementation
To accomplish this today, I do a couple Bad Things(TM) as far as security is concerned: the .pfx file is in source control, and the password for it is in the build script (also in source control). This means that any developers with access to source code repository can take the pfx file and do whatever nefarious things they'd like with. (We're a relatively small dev shop and trust everyone with access, but clearly this still isn't good).
The ultimate secure implementation
All I can find about doing this "correctly", is that you:
Keep the pfx and password on some secure medium (like an encrypted USB drive with finger-based unlock), and probably not together
Designate only a couple of people to have access to sign files
Only sign final builds on a non-connected, dedicated machine that's kept in a locked-up vault until you need to bring it out for this code-signing ceremony.
While I can see merit in the security of this.. it is a very heavy process, and expensive in terms of time (running through this process, securely keeping backups of certificates, ensuring the code-signing machine is in a working state, etc).
I'm sure some people skip steps and just manually sign files with the certificate stored on their personal system, but that's still not great.
It also isn't compatible with signing files that are then used within the installer (which is also built by the build server) -- and this is important when you have an installed .exe that has a UAC prompt to get admin access.
Middle ground?
I am far more concerned with not presenting a scary "untrusted application" UAC prompt to users than proving it is my company. At the same time, storing the private key AND password in the source code repository that every developer (plus QA and high-tier tech support) have access to is clearly not a good security practice.
What I'd like is for the CI server to still sign during the build process like it does today, but without the password (or private key portion of the certificate) to be accessible to everyone with access to the source code repository.
Is there a way to keep the password out of the build or secure somehow? Should I be telling signtool to use a certificate store (and how do I do that, with 3 build agents and the build running as a non-interactive user account)? Something else?

I ended up doing a very similar approach to what #GiulioVlan suggested, but with a few changes.
MSBuild Task
I created a new MSBuild task that executes signtool.exe. This task serves a couple main purposes:
It hides the password from ever being displayed
It can retry against the timestamp server(s) upon failures
It makes it easy to call
Source: https://gist.github.com/gregmac/4cfacea5aaf702365724
This specifically takes all output and runs it through a sanitizer function, replacing the password with all *'s.
I'm not aware of a way to censor regular MSBuild commands, so if you pass the password on commandline directly to signtool.exe using it will display the password -- hence the need for this task (aside from other benefits).
Password in registry
I debated about a few ways to store the password "out-of-band", and ended up settling on using the registry. It's easy to access from MSBuild, it's fairly easy to manage manually, and if users don't have RDP and remote registry access to the machine, it's actually reasonably secure (can anyone say otherwise?). Presumably there are ways to secure it using fancy GPO stuff as well, but that's beyond the length I care to go.
This can be easily read by msbuild:
$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\1 Company Dev#CodeSigningCertPassword)
And is easy to manage via regedit:
Why not elsewhere?
In the build script: it's visible by anyone with source code
Encrypted/obfuscated/hidden in source control: if someone gets a copy of the source, they can still figure this out
Environment variables: In the Teamcity web UI, there is a detail page for each build agent that actually displays all environment variables and their values. Access to this page can be restricted but it means some other functionality is also restricted
A file on the build server: Possible, but seems a bit more likely it's inadvertently made accessible via file sharing or something
Calling From MSBuild
In the tag:
<Import Project="signtool.msbuild.tasks"/>
(You could also put this in a common file with other tasks, or even embed directly)
Then, in whichever target you want to use for signing:
<SignTool SignFiles="file1.exe;file2.exe"
PfxFile="cert.pfx"
PfxPassword="$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\1 Company Dev#CodeSigningCertPassword)"
TimestampServer="http://timestamp.comodoca.com/authenticode;http://timestamp.verisign.com/scripts/timstamp.dll" />
So far this works well.

One common technique is to leave keys and certificates in Version Control, but protect them with a password or passphrase. The password is saved in environment variables local to the machine, which can be easily accessed from scripts (e.g. %PASSWORD_FOR_CERTIFICATES%).
One must be careful not to log these values in plain text.

Related

Per Machine App Registration

I'm building an installer with WiX to install a program, per machine (not per user), and it gives them the option to register the program. Registration involves entering user name and organization (or accepting some defaults from Windows settings), and entering a valid registration key. When the registration key is validated, I write registry settings in the HKEY_LOCAL_MACHINE area with this information. Under Windows, when one runs the MSI, it prompts automatically for an admin password to be able to set registry values in HKEY_LOCAL_MACHINE. So far life is good...
I am including an option in the MSI to give the user the option to defer registration until a later point in time. However, if the user is a normal user and they are running the application, if I have a dialog in the app which prompts for name/org/product-key, Windows doesn't the app to write the information to HKEY_LOCAL_MACHINE. So a user cannot use the application itself, running as a normal user, to perform a registration per-machine as the MSI does after prompting for admin credentials.
My thought then was, for post-installation registration, to either (a) find a way from within the application to elevate privileges, with a prompt for admin credentials, allowing it to write HEKY_LOCAL_MACHINE (is this possible?), (b) include an option in the installer that, when run and the app is already installed and not registered, walks through the registration as it would during a normal install. It would then prompt for the admin credentials and life is good again. Alternatively, (c) create a separate MSI that just does registration, install this with the program, and call this MSI from the program when the user selects the "Register..." command in the program.
I've not seen either of these approaches done by any applications before, so I'm not sure either is a good approach. Other than that, however, I'm not sure how, post-installation, I can conveniently allow the user to do a per-machine app registration. Ideally, I'd like to be able to do it from a command within the app, but re-running the installation MSI would be minimally acceptable.
How is this normally done? Or are per-machine installations even normally accompanied by per-machine registrations?
Very good question - I have dealt with this issue many times myself. No ideal solutions, but several options (as you have already discovered).
Before answering, I want to point out that I have a strong aversion against doing too much registration and configuration in the setup itself. It is error prone, and much better done in the application itself for a plethora of reasons: Installer with Online Registration for Windows Application (recommended quick read - tidbits from real life experience).
Writing to HKCU
As you already know, one option is to keep the license key and registration in HKCU only. This is often acceptable unless you want to share a license key between many users on the box. The license key, if added to HKCU, will also generally roam with the user to other computers - which can be helpful or desirable.
Personally, this is the option I prefer: not registering anything in the setup, but writing to HKCU or the user-profile from the application (as explained in the link above as well). As stated, the only drawback is that you can't write a shared license key to HKLM so it applies to all users and not just a single user. This appears to be the core of the problem you are describing.
Writing to HKLM
Setup writes HKLM: Write the HKLM license key (and registration) during the setup to HKLM as Phil has described above using the default Windows Installer properties (just listing this as an option - which you already know about). This should work OK in my opinion - but your issue seemed to be to allow the "deferred registration".
Custom HKLM ACL permissioning: In order to write to HKLM from your non-elevated application, one way to do it is to use your setup to apply custom ACL permissions to the location in HKLM where you want to write the shared registry key from your application. Your application can then freely update this specific location in HKLM at any time without elevated rights. You simply add ACL write access for "Users".
WiX supports this, but I don't have a sample for you available, please check the WiX documentation for permissioning.
Using custom permissioning is generally frowned upon (and I agree it is not ideal design), but it allows any user to add a license key to HKLM without any elevation after the install (and also allows any users to delete it - which can be a problem).
See section 14 here for a quick description of why custom permissioning is not generally recommended: How do I avoid common design flaws in my WiX / MSI deployment solution?
In summary, I don't generally suggest setting custom permissions, but it will definitely work. I have done it myself when client requirements are such that this is the only thing they will accept. It will violate logo requirements for Windows applications, but it should be less serious than the security issues that result from option 3 below.
Run app as admin: If you don't want to apply ACL permissions, I believe you can prompt the user for admin rights for your application as described here (I believe this is what Phil referred to in his comment if I understand correctly):
How do I force my .NET application to run as administrator? (the legendary Hans Passant - one more answer).
This is most definitely not recommended (but we want to show people what is possible too). Your whole application will run with admin rights all the time, which is not a good idea at all.
Doing this will violate a key part of logo requirements for Windows applications and you will also open your application up to attack from malware.
Definitely try to make your users understand the consequences of this "easy fix". I would make sure to put all responsibility on the client if they go for this option - they must understand what they are doing.
Note that you should be able to use this manifest approach to launch a separate EXE with elevated rights to do only the registration. See next bullet point.
Elevate app on demand: I am not familiar with the technical details of elevating your application on demand whilst it is running - as you invoke a dialog or feature that needs HKLM access. Perhaps Phil knows a way to achieve this? I found some links though:
Elevating during runtime (from Code Project)
How to elevate privileges only when required? (good read)
Skimming the linked content above, it seems like you can launch a separate EXE with elevated rights to do your registration - a known option for you I assume.
Would love to hear back if this is something you decide to try. Could be useful for all of us.
Internet validation: Just throwing an option out there: what I often want to do is to put the whole registration license key validation online from within the application (never, ever try this from the setup, just so that is mentioned - a setup that tries to access the Internet might be the biggest deployment anti-pattern of all - at least for now).
I write the license key from the setup, and the validation of it takes place on application launch against a server on the Internet. Then there is no validation code in your application or your setup to crack.
You need an Internet "handshake" and you can repeat this process per user - allowing you to tightly control who is using your license key.
Nothing is ever easy, and proxy server issues could cause problems. Corporate deployment would also mean that such "online activation" is frowned upon. They want applications fully installed after deployment.
Separate registration MSI: I would prefer not to create a separate MSI just for the registration process as you mention in your question. This just seems like unnecessary complexity that can break easily. For one thing you get a dual source problem that must be permanently maintained. I would guess that this could become a classic support issue.
Re-run original MSI: I am honestly not sure if re-running your original setup to do the registration will launch it elevated or not. I think it will be elevated (should be, can't see any reason why it shouldn't - the MSI database stores a flag to determine if elevation is required "Word Count"), and then you should be able to add your registration details provided you access the registration dialog from the setups "modify" or "repair" modes.
This kind of registration is usually done using the standard Windows Installer properties so it just works.
If you have a verification key then it's typically associated (in the dialog) with the standard PIDKEY property which then after validation becomes the ProductId property.
https://msdn.microsoft.com/en-us/library/windows/desktop/aa370826(v=vs.85).aspx
Similarly the user name and company name are associated in the dialog with the USERNAME and COMPANYNAME properties.
After this, they're available through (Win32) MsiGetProductInfo () by asking for RegOwner etc:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa370130(v=vs.85).aspx
or similar APIs (WMI does some of this).
So generally speaking you just set the properties from the dialogs and it all just works with no need for you to write them to the registry.

How to secure/encrypt Inno Setup from decompiling

I am using an Inno Setup Tool to pack/setup all my files (dll, exe, jpg, etc).
But I found that there is a software called InnoExtractor which can really open my setup and read all the scripts and also extract all the files, since I need to hide/protect my files in setup I spent a lot of time/efforts to secure my setup.exe which was generated from Inno Setup, but I found some people saying add a password to Inno Setup Script, but this is also a wrong because the client knows that password and he can simply use InnoExtractor and extract everything even it was protected by Password! is not it!?
Now, I just ask if there someone can suggest me to solve this problem. In fact I embed XML files and DLL which is used to install specific files at client side according to the client machine, but if the client extract all DLLs to his machine then it will be a catastrophe! I need a way to prevent the client from seeing/extracting my setup.exe!
There's no way to protect code from an user, if you need to be able to run the same code on the user's machine. Once you deliver files to client's machine, no matter what method you used to pack them, the client can extract the files.
You can only make it harder, but there's no absolute solution.
More standard tools you use, more easy it is to decompile the code. If you want to make decompiling hard, make your custom installer, instead of relying on a standard installer tool (like Inno Setup).
Probably the only safe way is to use some online service.
You can encrypt the files with some very strong cipher (each file/DLL with a different encryption key). The installer will ask the user for some password, and will send the password to some online service. The online service, after verifying the password, will send back a decryption key for the DLL that you allow the client to install. This will allow the installer to decrypt only the DLL for that client.
Another alternative is that the installer will actually download the DLL from a server, only after you verify the client.
There's no way to 100% protect your installer from an attacker. If someone want to crack it then it can do it.
What you can do:
1) Encrypt the files with some custom (3rd party) system or use [Setup] Encryption directive
2) Modify Inno Setup - download sources, change them and compile again
3) Place sensitive files and data on server and download them during setup (+ encrypt)
4) [Code] section cannot be entirely unpacked, place some calculations or file operations there

Create elevated console/cmdline app windows - suggestions?

Looking for suggestions on how to go about the following, i.e what would be the best language to do it in etc, third party tools are a no :(
I've been tasked to create some sort of windows shell/command line interface that will allow a standard users to install a specific set of applications (configurable by administrators) (installation requires Admin/UAC elevation) due to security restrictions the user cannot have elevated privileges so they'll be able to run the shell as a standard user and it would have hidden/encrypted credentials built in to run the installs as.
Some of the requirements are as follows:
It would need to work on Server 2008 R2, 2012 r1 and 2012 r2
The credentials used to perform the install would have to be hidden (encrypted) from the end user.
Ideally it could work by us providing some config to it prior to handing that server over to the customer and limit what it could be used to install to a particular .exe or .msi (so we know of a need to install an app, we are advised of the name of the install and can logon and can enter it into a form maybe so only that app can be installed, then hand the server over to the customer who runs the same utility or shell extension or whatever and can then install their app.
Even more ideally it was more intelligent than that and some means of ensuring any .msi was indeed installing the application that the msi name related to (seems unlikely but just in case a normal user created an .msi to grant himself further admin access as per http://blogs.technet.com/b/fdcc/archive/2011/01/25/alwaysinstallelevated-is-equivalent-to-granting-administrative-rights.aspx )
Ideally its lifespan would be limited in terms of time (unsure if this could be for example to x number of days).
Any pointers on how to go about this, seems like a good challenge :)
Thanks for reading all that!
Mike
Thanks for the responses,
I managed to do this in C#, with no prior experience in the language :)
The application has 2 parts to it, a GUI and a service. It works by having the application send an install command via IPC to it's counterpart elevated service. (Thanks Hans Passant for pointing me in the right direction there). The service initiates the installer under it's own elevated account but displays the installer GUI on the users session. Files are HMACSHA1 checksum validated prior to install, on both the app and the service.
Thanks,
Mike
If a user requires the ability to install application in the Program Files folder, then instruct the domain administrator to give Full Control of the Program Files folder to Everyone:
Just because the default setting forbids standard users from modifying programs, doesn't mean you have to keep it that way. Windows is a secure operating system that gives you the capability to keep it secure.
If your administrator only wants some users to be able to modify the contents of the Program Files folder, then only give that permission to certain users.
The better solution is to re-design the applications so that they do not install in a (by default) protected location. Have them instead install in:
%APPDATA_LOCAL%\Contoso\Frobber\Grob.exe
e.g.
D:\Users\Ian\AppData\Local\Contoso\Frobber\Grob.exe
A user is always allowed to write anything in their own profile folder.

SignTool - secure Workflow?

we are new at code signing, so im interested in your experiences how to use the sign tool without exposing the certificate to everyone in the company.
Can everyone in your company do code signing?
Do you give the certificate to every person in your company?
We want do some automatic workflow, like the developers drop theire files into a directory and every file get be signed.
Thanks for your advice.
My company has a VBScript wrapper that automates the signing and validation process. The VBScript, signtool.exe, capicom.dll and a PFX (containing the certificate chain and private key) all sit on a password protected network share.
Whenever someone needs to sign a binary, they can simply drag and drop the file onto the VBScript; and it handles the rest. Although, since our build process has become almost completely automated, it has fallen into disuse.
On the down side, it is a VBScript. So the password to the private key is visible, but that was the reason for password protecting the share.
Addendum
You could do something similar where it would sign any files within a folder/share and configure Windows Scheduled Tasks to execute the script every few minutes. After signing, it would need to move the files to a different folder, but that is easy enough. This would allow you to restrict access to the script, certificate, private key and the folder where files are signed.

Providing an application data update from a website

I need to provide an update to application data as a download from a website. The update would actually just be the replacing of some data files with some updated ones.
The update, which I assume would be some sort of setup package type program, would need to be able to do the following:
access the file system and registry
to determine where files should be
copied to
supply the files to be copied
provide strong security so the data files cannot be downloaded or used by the wrong people
What would be best way to achieve all of the above?
I would suggest to use either
Java Web Start, for Java
ClickOnce Deployment, for .NET
These technologies are meant to distribute software over networks.
(I think that developing something similar yourself can turn to be something rather complicated.)
There are a number of comprehensive update manager and delivery services available from commercial software vendors if you don't want to write something from scratch yourself.
TrueUpdate
InstallShield
ClickOnce
... plus more, I'll leave you to research yourself :)
Your choice will depend on your chosen language, existing setup methods, targeted operating systems and budget.
We just use standard MSI installers/upgrades and wrote our own update manager/update delivery service. You'll need to weigh up own resources and development expense to decide if it's worth purchasing a commercial product, or developing something in-house.
I've used AdvancedInstaller - a very capable free version is available. It is a fully-fledged MSI installer, so it can read/write to the registry and install files to "Program Files" that normally requires admin privileges. It also supports application updates out of the box. You can publish updates and have them automatically downloaded and installed.
As to security, this is not really the realm of an Installer but part of the webserver where you host the files. You could use a password protected folder, or for stronger prevention, client SSL certificates. The latter would work well with automatic updates.
An alternative is to string together a solution from a number of readily available components:
use a batch file to perform the download that is executed regularly. You can schedule batch files using the Windows Task Scheduler.
The batch file will use the Windows REG command to read values from the registry, and use those values to invoke rsync. rsync is a file synchronization command that can be run through ssh. If you configure ssh with public key authentication, you restrict access to specific clients of your choosing, while allowing automated access (no password required.) The key with rsync is that if the files are up to date, no download is performed.
This article explains how to sync files from a server to a notebook using rsync and ssh, and explains how to set up rsync and ssh using Cygwin.
See also
Windows REG command
ssh (Wikipedia) and openssh manpages.
rsync manpage

Resources