We recently purchased a DigiCert EV code signing certificate. We are able to sign .exe files using signtool.exe. However, every time we sign a file, it prompts for the SafeNet eToken password.
How can we automate this process, without user intervention, by storing/caching the password somewhere?
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();
}
}
}