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". SafeNet Advanced View

1. Export your public certificate to a file from the SafeNet Client Exporting the Certificate to a File

2. Find your private key container name
Private Key Container Name

3. Find your reader name 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 UI
  • password is your token password
  • name 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:

enter image description here

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();
      }
   }
}