Guide to signing unsigned drivers
***UPDATE***
An updated (and more readable!) PART 1 tutorial can be found here: http://www.alkanesolutions.co.uk/2013/10/23/a-guide-to-signing-un-signed-drivers/
An additional PART 2 tutorial (debugging a driver install) can be found here: http://www.alkanesolutions.co.uk/2016/04/29/guide-signing-un-signed-drivers-part-2/
I thought I'd write this post to give something back to the community, as it took me ages to find out for myself and get working so hopefully it will assist others. Some of the info in this post was extracted from some great posts from AngelD, so kudos to him for that. It's only been tested in an XP environment, but here goes...
Tools you need: (most are from the Windows Driver Kit):
Inf2Cat.exe (To generate the unsigned catalog file from our INF)
In the same folder as Inf2Cat.exe I have the following DLLs:
Microsoft.Whos.Shared.IO.Cabinets.dll
Microsoft.Whos.Shared.IO.Catalogs.dll
Microsoft.Whos.Shared.Xml.InfReader.dll
Microsoft.Whos.Winqual.Submissions.SubmissionBuilder.dll
Microsoft.Whos.Xml.NonXmlDataReader.dll
Makecert.exe (Used to create our certificate)
Cert2spc.exe (Create Software Publisher's Certificate (SPC) from our certificate)
Signcode.Exe (Sign our catalog file with an Authenticode digital signature)
Certmgr.exe (Used to add and delete our certificate to the system root)
DifxApp.msm (Difx Merge Module to install the driver)
**********************************************
*****INTRODUCTION******************************
**********************************************
Now we have our toolset in place, let's package the unsigned Captain Planet printer driver. We're packaging this driver for a customer called 'Planeteers Ltd'.
Let's assume we've captured the Captain Planet printer driver using a snapshot tool. We can see from the resultant snapshot that there is a file in [WindowsFolder]\inf called 'captainplanet.inf'. There are also files called 'captainplanet.sys' and 'captainplanet.dll' in [SystemFolder]spool\drivers\w32x86.
All of these files make up the Captain Planet printer driver so let's create a folder anywhere on your work machine
(say, "c:\cpdriver") and copy the three files to it.
We should now have our unsigned driver in a temporary folder called "C:\cpdriver" which contains:
captainplanet.inf
captainplanet.sys
captainplanet.dll
Now let's generate a customer certificate, so we can sign this (and many more) driver(s).
**********************************************
*****SIGNING THE DRIVER*************************
**********************************************
1. Create .cat (catalog) file for driver.
We notice that the Captain Planet driver doesn't contain a cat file, so we'll need to generate one.
Open the .INF file in a text editor. Ensure that under the [version] section that you have an entry specifying a .cat file. If it's not there, add the line
at the end of the section. For example:
"captainplanet.cat" is the name of the cat file that we want to generate. Not having a line specifying this will result in an "error 22.9.4 - Missing 32-bit catalog file entry" when we run Inf2Cat.exe. "NTx86" represents the Windows 2000 x86-based platforms.
[version]
Signature=xxxxxx
Provider=xxxxxx
CatalogFile.NTx86=captainplanet.cat
Command line:Inf2Cat.exe /driver:"
Example: Inf2Cat.exe /driver:"C:\cpdriver" /os:XP_X86
Running this successfully will generate captainplanet.cat in the 'C:\cpdriver' folder.
2. Create authenticode certificate and set private key
Create another folder called 'c:\PlaneteersLtd_certificate'. It is here where we'll create our customer-specific certificate and private key. Remember that this certificate can be reused multiple times for the customer (Planeteers Ltd) to sign different drivers, so keep naming conventions generic to your customer.
Command line:MakeCert.Exe -r -pe
Example:
makecert.exe -r -pe "c:\PlaneteersLtd_certificate\PlaneteersLtd.cer" -n CN="Planeteers Ltd" -sv "c:\PlaneteersLtd_certificate\PlaneteersLtd.pvk" -len 2048
Running this will ask you to set a private key. Make a note of this key! Running this command will generate:
c:\PlaneteersLtd_certificate\PlaneteersLtd.cer and c:\PlaneteersLtd_certificate\PlaneteersLtd.pvk
(I think certificates of this kind are actually supposed to be used for development/testing as opposed to a live environment. It's probably advisable to purchase a certificate from Verisign/Comodo/whoever if you have the budget.)
3. Create Software Publisher's Certificate (SPC) from our certificate
Command Line:Cert2Spc.Exe
Example: cert2spc.exe "c:\PlaneteersLtd_certificate\PlaneteersLtd.cer" "c:\PlaneteersLtd_certificate\PlaneteersLtd.spc"
This will generate c:\PlaneteersLtd_certificate\PlaneteersLtd.spc
4. Sign the catalog file
Command line:signcode.exe -spc
(Yes....I know it says 'timstamp.dll' but that is correct) This will prompt you for the private key you set earlier. Enter it when prompted.
Example:SignCode.Exe -spc "c:\PlaneteersLtd_certificate\PlaneteersLtd.spc" -v "c:\PlaneteersLtd_certificate\PlaneteersLtd.pvk" -t http://timestamp.verisign.com/scripts/timstamp.dll "C:\cpdriver\captainplanet.cat"
**********************************************
*****ADDING THE CUSTOMER CERTIFICATE**********
**********************************************
The catalog for our driver is now signed. Every time we install this driver using DifxApp, we need to ensure the customer certificate is installed on the machine before DifxApp installs the driver. To do this, we use CertMgr.exe in two Custom Actions (CA) - one to add the certificate on install, and one to remove it on uninstall. We can do this in two ways:
a) Create the two CAs in every single driver package you do
b) Create a merge module which can easily be incorporated in every driver package you do
In my opinion option b) would provide less hassle for me because after all, we want our certificate to be easily re-usable for multiple driver packages. So for now, we'll do option b).
1. Create a new merge module and add captainplanet.cer to the SystemFolder of the MSM (or wherever you deem appropriate)
2. Go to the Custom Action (CA) table and create 2 CAs, both are an 'Exe stored in binary table' and 'Deferred in a System Context'.
If you use the CA wizard, you should stream 'certmgr.exe' into your binary table. Here's what (roughly) your CustomAction table should look like after you've made them:
Name: addCertificate
Type: 3074
Source: certmgr
Target: -add "[SystemFolder]PlaneteersLtd.cer" -s -r localMachine ROOT
Name: removeCertificate
Type: 3074
Source: certmgr
Target: -del "[SystemFolder]PlaneteersLtd.cer" -s -r localMachine ROOT
And here is the Binary table:
Name: certmgr
Data:
Of course, using the wizard to do both CAs may result in two entries in your binary table containing the same exe (certmgr.exe). Obviously this is a waste, so remove one of them and set the 'Source' column in your CustomAction table appropriately.
3. Go to the ModuleInstallExecuteSequence table (Where
Action: addCertificate
Sequence:
BaseAction: InstallFiles
After: 1
Condition: Not Installed
Action: removeCertificate
Sequence:
BaseAction: InstallInitialize
After: 1
Condition: REMOVE~="ALL"
Action: InstallFiles
Sequence: 4000
BaseAction:
After:
Condition:
Action: InstallInitialize
Sequence: 1500
BaseAction:
After:
Condition:
The sequencing above is important as the addCertificate CA needs to run after the certificate is put down on the machine (after InstallFiles) and the removeCertificate CA needs to run before the certificate is removed from the machine. It also needs to run before DifxApp installs the driver.
**********************************************
*****CREATE DRIVER PACKAGE********************
**********************************************
Great. At this point we should now have a signed driver, and a merge module which installs our customer certificate. Now we can create the MSI package
which installs our signed driver:
1. Create a new ISM/WSI project and make a folder somewhere for your driver (one folder per driver remember).
Let's say:
"[ProgramFilesFolder]CaptainPlanetDriver" for this example. This folder will contain all the files in 'c:\cpdriver' on our work machine:
captainplanet.inf
captainplanet.sys
captainplanet.dll
captainplanet.cat (the one we've just generated!)
Remember that all these files should be in the SAME COMPONENT as well as the same folder (one .inf per folder), and the keypath of the component needs to be the .inf file!
Let's call the component: "CaptainPlanet_DRIVER"
2. Install the driver using DifxApp.
When we add the latest version of the DifxApp.msm merge module, it will create a table in the project called "MsiDriverPackages". Installshield and Wise have slightly
different wizards to install a driver, so I'll just show you roughly how the MsiDriverPackages table should be populated:
Component: CaptainPlanet_DRIVER
Flags: 7
Sequence: 1
ReferenceComponents:
Once this is done, compile your .MSI. Ensure in your .MSI that your 'addCertificate' CA runs after 'installFiles' and before 'MsiProcessDrivers' in the installExecuteSequence.
At last, we're done!
Now I'd highly recommend testing your MSI install with verbose logging enabled, as the DifX merge module does write some half-decent logging which can assist you. For example, just recently DifxApp verbose logging warned me that some DLLs (part of the driver) were not being copied to the driver store. This was the reason why my driver wasn't working, and so I had to edit the .INF file [SourceDisksFiles] section (Add the relevant files which weren't being copied to the driver store), re-generate the cat file, re-sign it and then re-add these updated files to my MSI (Note there was obviously no need to go fiddling with my MSM as the certificate remains the same).
It's also always best to test your driver with the appropriate hardware.
Anyway. I hope this guide can be of some help to others. If you break your machine, or yourself, during implementing this guide then don't blame myself. It's only meant as a guide. Please feel free to comment/correct/bug fix.
Captain Planet.
Answers (33)
First of all, thanks for the guide. It has been really helpful, although some things have changed if you want to do this for Windows 7. For one part, I had to discover that some tools didn't exist anymore and got replaced. Anyways, here's my findings... :
- Inf2Cat.exe also needs the file WindowsProtectedFiles.xml which you didn't list above.
- As one might have guessed, use Inf2Cat.exe with the flag /os:7_X86
- signcode.exe is replaced by signtool.exe in the latest versions of both the WDK and Visual Studio. And because signtool expects a different input, an extra step is introduced:
A PFX file needs to be generated with the PVK and SPC files. This is done by a tool called pvk2pfx.exe (also in the WDK)
pvk2pfx.exe Usage:
pvk2pfx -pvk <pvk-file> [-pi <pvk-pswd>] -spc <spc-file> [-pfx <pfx-file> [-po <pfx-pswd>] [-f]]
-pvk <pvk-file> - input PVK file name.
-spc <spc-file> - input SPC file name.
-pfx <pfx-file> - output PFX file name.
-pi <pvk-pswd> - PVK password.
-po <pfx-pswd> - PFX password; same as -pi if not given.
-f - force overwrite existing PFX file.
if -pfx option is not given, an export wizard will pop up. in this case, options -po and -f are ignored.
So the command line should look similar to this:
pvk2pfx.exe -pvk "c:\PlaneteersLtd_certificate\PlaneteersLtd.pvk" -spc "c:\PlaneteersLtd_certificate\PlaneteersLtd.spc" -pi <private key password>
And now signtool.exe can be used to sign the catalog file:
signtool.exe sign /f "c:\PlaneteersLtd_certificate\PlaneteersLtd.pfx" /p <password> /t http://timestamp.verisign.com/scripts.timstamp.dll "C:\cpdriver\captainplanet.cat"
Comments:
-
- dan@kace.com 12 years ago
Thanks a lot Captain Planet, again.
And also to Rheuvel for the addional info
Great tut, just a bit tricky to get all the tools together. Dont understand why MS forces one to download all SDK just for a simple exe
In response to shh.killer:
To test that the files in your driver package are all signed, first get yourself a copy of SignTool.exe. I think this is part of the .Net framework, the Windows Driver Kit (WDK) and also installed with Installshield (not sure about Wise).
Anyway, ensure you install your certificate to the 'Trusted Root Certification Authorities'. Easiest way to do this is to double click your certificate file, click 'Install Certificate', click 'Next', select 'Place all certificates in the following store', Click 'Browse', select 'Trusted Root Certification Authorities' and click 'Ok', click 'Next', click 'Finish'.
Verify that it has been installed to this location by:
Open Internet Explorer > Tools > Internet Options > 'Content' tab > 'Cetificates' button and check under the 'Trusted Root Certification Authorities' tab for your certificate. (or alternatively at the Certificates MMC Snap-in and do it that way...)
Once you see it's there, you can run the following command line from a DOS prompt (based on the example above):
signtool.exe verify /pa /v /c C:\cpdriver\captainplanet.cat C:\cpdriver\captainplanet.inf
...and with any luck, you'll get a similar output to this:Verifying: C:\cpdriver\captainplanet.inf
File is signed in catalog: C:\cpdriver\captainplanet.cat
Hash of file (sha1): 8AC92B48A213FC158FFAA8EE71B2E8FAE02BE63B
Signing Certificate Chain:
Issued to: Planeteers Ltd
Issued by: Planeteers Ltd
Expires: Sat Dec 31 23:59:59 2039
SHA1 hash: 6579183F3564D2E99B5EEFAE7433ADEE7A712188
The signature is timestamped: Thu Sep 16 14:42:57 2010
Timestamp Verified by:
Issued to: Thawte Timestamping CA
Issued by: Thawte Timestamping CA
Expires: Thu Dec 31 23:59:59 2020
SHA1 hash: BE36A4562FB2EE05DBB3D32323ADF445084ED656
Issued to: VeriSign Time Stamping Services CA
Issued by: Thawte Timestamping CA
Expires: Tue Dec 03 23:59:59 2013
SHA1 hash: F46AC0C6EFBB8C6A14F55F09E2D37DF4C0DE012D
Issued to: VeriSign Time Stamping Services Signer - G2
Issued by: VeriSign Time Stamping Services CA
Expires: Thu Jun 14 23:59:59 2012
SHA1 hash: ADA8AAA643FF7DC38DD40FA4C97AD559FF4846DE
Successfully verified: C:\cpdriver\captainplanet.inf
Number of files successfully Verified: 1
Number of warnings: 0
Number of errors: 0
ORIGINAL: captain_planet
I'm sure I only ever received that error when using signcode.exe? Either your timestamp path may be incorrect (Remember it's 'http://timestamp.verisign.com/scripts/timstamp.dll' andNOT 'http://timestamp.verisign.com/scripts/timstamp.dll') or your corporate proxy/firewall may be hindering the process..... e
Found this was because i was using IE6! upgraded to IE7 and away it went. Still not got my package to install. Using wisepackage stud 7.
verbose log says something about the .inf file not being signed.
Does the .inf need signed also?
I have a quick question regarding the Authenticode Certificate. I rang Comodo and asked them about providing me with a live version of the certificate and they had never heard of such a thing. They only provide SSL Certs and Code Signing certificates. Any Idea how much one of these certs would cost?
AngelD - Good suggestion, thanks. I did think about adding a bit more detail re: [SourceDisksFiles] but I didn't want to dilute the guide too much and make it too long. Maybe when I get a second I can add another, separate post in this thread which explains a bit about INF files and how they work? In honesty, before I do that I'll have to brush up a bit on them myself.... [;)]
Comments:
-
Hi captain,
IS it legal to redistribute my self signed certificate. could you please reply to my email id???
sethuuraman@gmail.com - sethuuraman 12 years ago
I can't seen to get past the stage of signing the cat file :(
Error: Invalid timestamp http address
Error: TimeStamping Failed. Result = 80070001, (-2147024895)
when creating authenticode cert and running the bellow command with all my details
MakeCert.Exe -r -pe <path to .cer file you want to generate> -n CN=<certificate name> -sv <path to .pvk file you want to generate> -len 2048
The only way this comand would work for me was to remove -pe and -len 2048
My makecert didn't seem to recognise these commands. Have i got a old makecert.exe?
Im guessing me removing these commands is whats stopping the cert from getting the time stamp.
i have a problem about signing;
i created .cer, .pfx, .cat and .pvk. The last step of signing is use signtool.exe. I entered the parameters like ur writing but the result is;
C:\WinDDK\7600.16385.1\bin\amd64>signtool verify /pa /v /c C:\Users\nnn\Desktop
osss\apco25vpcc.cat C:\Users\nnn\Desktop\osss\apco25_vpcc_device_driver.inf
Verifying: C:\Users\nnn\Desktop\osss\apco25_vpcc_device_driver.inf
File is signed in catalog: C:\Users\nnn\Desktop\osss\apco25vpcc.cat
Hash of file (sha1): 0A7522B6BD7A3A2EC7635E920C23C22BA6070809
SignTool Error: No signature found.
Number of files successfully Verified: 0
Number of warnings: 0
Number of errors: 1
C:\WinDDK\7600.16385.1\bin\amd64>
Where did i wrong?
so that the conversation will remain readable.