Automate Extended Validation (EV) code signing
Expanding on answers already in this thread, it is possible to provide the token password using the standard signtool program from microsoft.
0. Open SafeNet Client in Advanced View
Install paths may vary, but for me the SafeNet client is installed to: C:\Program Files\SafeNet\Authentication\SAC\x64\SACTools.exe
Click the gear icon in the upper right to open "advanced view".
1. Export your public certificate to a file from the SafeNet Client
2. Find your private key container name
3. Find your reader name
4. Format it all together
The eToken CSP has hidden (or at least not widely advertised) functionality to parse the token password out of the container name.
The format is one of the following
[]=name
[reader]=name
[{{password}}]=name
[reader{{password}}]=name
Where:
reader
is the "Reader name" from the SafeNet Client UIpassword
is your token passwordname
is the "Container name" from the SafeNet Client UI
Presumably you must specify the reader name if you have more than one reader connected - as I only have one reader I cannot confirm this.
5. Pass the information to signtool
/f certfile.cer
/csp "eToken Base Cryptographic Provider"
/k "<value from step 4>"
- any other signtool flags you require
Example signtool command as follows
signtool sign /f mycert.cer /csp "eToken Base Cryptographic Provider" /k "[{{TokenPasswordHere}}]=KeyContainerNameHere" myfile.exe
Some Images taken from this answer: https://stackoverflow.com/a/47894907/5420193
There is no way to bypass the login dialog AFAIK, but what you can do is configure the SafeNet Authentication Client so it only asks it once per login session.
I quote the SAC doc (found once installed in \ProgramFiles\SafeNet\Authentication\SAC\SACHelp.chm
, chapter 'Client Settings
', 'Enabling Client Logon
') here:
When single logon is enabled, users can access multiple applications with only one request for the Token Password during each computer session. This alleviates the need for the user to log on to each application separately.
To enable this feature which is disabled by default, go to SAC advanced settings, and check the "enable single logon" box:
Restart your computer, and it should now only prompt for the token password once. In our case, we have more than 200 binaries to sign per each build, so this is a total must.
Otherwise, here is a small C# console sample code (equivalent to m1st0 one) that allows you to respond automatically to logon dialogs (probably needs to run as admin) (you need to reference from your console project (UIAutomationClient.dll
and UIAutomationTypes.dll
):
using System;
using System.Windows.Automation;
namespace AutoSafeNetLogon {
class Program {
static void Main(string[] args) {
SatisfyEverySafeNetTokenPasswordRequest("YOUR_TOKEN_PASSWORD");
}
static void SatisfyEverySafeNetTokenPasswordRequest(string password) {
int count = 0;
Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent, AutomationElement.RootElement, TreeScope.Children, (sender, e) =>
{
var element = sender as AutomationElement;
if (element.Current.Name == "Token Logon") {
WindowPattern pattern = (WindowPattern)element.GetCurrentPattern(WindowPattern.Pattern);
pattern.WaitForInputIdle(10000);
var edit = element.FindFirst(TreeScope.Descendants, new AndCondition(
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit),
new PropertyCondition(AutomationElement.NameProperty, "Token Password:")));
var ok = element.FindFirst(TreeScope.Descendants, new AndCondition(
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button),
new PropertyCondition(AutomationElement.NameProperty, "OK")));
if (edit != null && ok != null) {
count++;
ValuePattern vp = (ValuePattern)edit.GetCurrentPattern(ValuePattern.Pattern);
vp.SetValue(password);
Console.WriteLine("SafeNet window (count: " + count + " window(s)) detected. Setting password...");
InvokePattern ip = (InvokePattern)ok.GetCurrentPattern(InvokePattern.Pattern);
ip.Invoke();
} else {
Console.WriteLine("SafeNet window detected but not with edit and button...");
}
}
});
do {
// press Q to quit...
ConsoleKeyInfo k = Console.ReadKey(true);
if (k.Key == ConsoleKey.Q)
break;
}
while (true);
Automation.RemoveAllEventHandlers();
}
}
}