Silently install root certificate in WiX

2019-03-27 14:50发布

How can I silently install root certificates from WiX? I'm installing some root and intermediate certificates, and for root certificates the system displays confirmation dialog showing basic certificate properties and thumbprint. This is relevant code I have, using WixIIsExtension mapped in namespace iis:

<Binary Id="RootCa" SourceFile="Certificates\RootCa.cer" />

<DirectoryRef Id="TARGETDIR">
  <Component Id="RootCa" Guid="...">
    <iis:Certificate
      Id="RootCa"
      BinaryKey="RootCa"
      Name="RootCa"
      StoreLocation="currentUser"
      StoreName="root"/>
  </Component>
</DirectoryRef>

<Feature ...>
    <ComponentRef Id="RootCa" />
</Feature>

标签: wix
4条回答
虎瘦雄心在
2楼-- · 2019-03-27 15:11

Custom action that Sunil provided is equivalent to Certificate component with attribute StoreLocation="localMachine". In my case installing in machine store makes more sense anyway, so I'll go with that. Original question still remains: how to silently install root certificate in user store. If someone has an answer to that question I'll mark it as correct answer.

查看更多
3楼-- · 2019-03-27 15:17

I am using custom action for same

<CustomAction Id="InstallCertificates" Directory="TARGETDIR" ExeCommand="[SystemFolder]Certutil –addstore –f &quot;root&quot; &quot;[INSTALLLOCATION]Certificates\CertificateName.cer&quot;" Execute="immediate" Return="ignore" />
查看更多
戒情不戒烟
4楼-- · 2019-03-27 15:24

I`ve been looking for an answer long time ago. So, thats what I have:

WiX Code:

<CustomAction Id="ImportCer.Props" Property="ImportCer" Value="[INSTALLDIR]ca\root.cer" />
<CustomAction Id="ImportCer" Execute="deferred"  FileKey="hsminst.dll" DllEntry="ImportCer" />

<CustomAction Id="ImportPfx.Props" Property="ImportPfx" Value="[INSTALLDIR]ca\super.pfx" />
<CustomAction Id="ImportPfx" Execute="deferred" FileKey="hsminst.dll" DllEntry="ImportPfx" />

C++ Code:

 extern "C" __declspec(dllexport) UINT __stdcall ImportCer(MSIHANDLE hInstall)
 {
      char szPath[MAX_PATH];

      GetModuleFileNameA(NULL, szPath, MAX_PATH);

      char certFilePath[MAX_PATH] = {0};
  DWORD certFilePathLen = MAX_PATH;
      MsiGetProperty (
           hInstall, 
           "CustomActionData", 
           certFilePath, 
           &certFilePathLen);

      wchar_t certFilePathW[MAX_PATH];
      MultiByteToWideChar(
           CP_ACP, 
           0, 
           certFilePath, 
           -1, 
           certFilePathW, 
           MAX_PATH);

      PCCERT_CONTEXT pCertCtx = NULL;

      if (CryptQueryObject (
         CERT_QUERY_OBJECT_FILE,
         certFilePathW,
         CERT_QUERY_CONTENT_FLAG_ALL,
         CERT_QUERY_FORMAT_FLAG_ALL,
         0,
         NULL,
         NULL,
         NULL,
         NULL,
         NULL,
         (const void **)&pCertCtx) != 0)
      {
          HCERTSTORE hCertStore = CertOpenStore (
              CERT_STORE_PROV_SYSTEM,
              0,
              0,
              CERT_STORE_OPEN_EXISTING_FLAG |
              CERT_SYSTEM_STORE_LOCAL_MACHINE,
              L"root");
          if (hCertStore != NULL)
          {
               if (!CertAddCertificateContextToStore (
                  hCertStore,
                  pCertCtx,
                  CERT_STORE_ADD_ALWAYS,
                  NULL))
               {
                  return -2;
               }

               if (!CertCloseStore (hCertStore, 0))
               {
                   return -3;
               }
          }
          else
          { 
                return -1; 
          }

          if (pCertCtx)
          {
               CertFreeCertificateContext (pCertCtx);
          }
      }
      return 0;
  }

  extern "C" __declspec(dllexport) UINT __stdcall ImportPfx(MSIHANDLE hInstall)
  {
       char certFilePath[MAX_PATH] = {0};
   DWORD certFilePathLen = MAX_PATH;
       MsiGetProperty (
            hInstall, 
            "CustomActionData", 
            certFilePath, 
            &certFilePathLen);

       wchar_t certFilePathW[MAX_PATH];
       MultiByteToWideChar(
            CP_ACP, 
            0, 
            certFilePath, 
            -1, 
            certFilePathW, 
            MAX_PATH);

       CRYPTUI_WIZ_IMPORT_SRC_INFO importSrc;
       memset(
           &importSrc, 
           0, 
           sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO));

       importSrc.dwSize = sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO);
       importSrc.dwSubjectChoice = CRYPTUI_WIZ_IMPORT_SUBJECT_FILE;
       importSrc.pwszFileName = certFilePathW;
       importSrc.pwszPassword = L"111111";
       importSrc.dwFlags = CRYPT_EXPORTABLE;

       HCERTSTORE serviceStore = CertOpenStore(
            CERT_STORE_PROV_SYSTEM,
            0,
            0,
            CERT_STORE_OPEN_EXISTING_FLAG |
            CERT_SYSTEM_STORE_CURRENT_USER,
            L"my");

       if (CryptUIWizImport(
            CRYPTUI_WIZ_NO_UI ,
            NULL,
            NULL,
            &importSrc,
            serviceStore
            ) == 0)
       {
           return -1;
       }
       return 0;
  }

Hope will help u

查看更多
Viruses.
5楼-- · 2019-03-27 15:26

I have had issues with installing certificates with WiX - two problems I got:

1. If you tell WiX to install in the trusted root certificates on the local machine, it does not work, installs in the Personal Store instead.
2. Permissions for certificates installed by WiX (when they have a private key) do not have the Everyone user set up. [You can change the permissions using MMC->Certificate Manager->Local Machine->(locate certificate with private key) Right Click->All Tasks->Manage Private key, which brings up a file permission dialog].

You can avoid both of these problems by using the microsoft winhttpcertcfg.exe tool. I use it in a batch file (see below), and use a WiX silent custom action to call the batch file. I let WiX install the tool, the certificates and the batch files before executing the batch. The batch can be setup to delete the tool and certificates after installation. It can also be used to start a service that WiX installed that depends on the certificates. The use of the batch greatly reduces the number of custom actions in your WiX file.

The consequence of not installing the certificates correctly was an intermittent error (some machines worked, some not) with a .net client "Could not create SSL/TLS secure channel" exception when doing an http request.

REM Batch file to install certificates using WinHttpCertCfg.exe
"[path to installed]winhttpcertcfg.exe" -i "[path to installed]ca.pfx" -a Everyone -c LOCAL_MACHINE\Root  > c:\temp\installcc.log
"[path to installed]winhttpcertcfg.exe" -i "[path to installed]server.pfx" -a Everyone -c LOCAL_MACHINE\My  >> c:\temp\installcc.log

I install the batch install and uninstall file in the product. Then in WiX - note the deferred and impersonated custom action.

<CustomAction Id="InstallCustomAction_Cmd" 
    Property="InstallCustomActionQt" 
    Value="&quot;cmd.exe&quot; /c &quot;[#InstallCustomAction.cmd]&quot;" 
    Execute="immediate" />

<CustomAction Id="InstallCustomActionQt" 
    BinaryKey="WixCA" 
    DllEntry="CAQuietExec"
    Execute="deferred" 
    Return="ignore" 
    Impersonate="yes"/>

<InstallExecuteSequence>
    <Custom Action="InstallCustomAction_Cmd" Before="InstallFinalize">NOT REMOVE</Custom>
    <Custom Action="InstallCustomActionQt" After="InstallCustomAction_Cmd" >NOT REMOVE</Custom>
...
</InstallExecuteSequence>
...
<Component Id="InstallCustomAction" Guid="{your-GUID}">
    <File Id="InstallCustomAction.cmd" KeyPath="yes"  
          Source="tools\InstallCloudConnectCustomAction.cmd" />
</Component>
查看更多
登录 后发表回答