WiX: Problem installing password protected PFX certificate - wix

I'm having some trouble getting a password protected PFX certificate to install through WiX.
I'm using WiX 3.5.2519.0.
I include a PFX file as follows:
<Binary Id="My.Binary"
SourceFile="$(var.ProjectDir)MyProject$(var.ConfigSuffix).pfx" />
The value of $(var.ConfigSuffix) varies based on solution configuration (e.g. " (Debug)", " (Stage)"). For "Release", it is set to an empty string.
I have various solution configurations, all but one use a non-password protected PFX certificate, "Release" uses a password protected PFX. I deal with this by conditionally defining $(var.PfxPassword) in "Release" configuration only, and then installing the certificate as follows:
<?ifdef $(var.PfxPassword) ?>
<iis:Certificate
Id="My.Certificate"
StoreName="root"
Overwrite="yes"
Name="My Web Site$(var.ConfigSuffix)"
Request="no"
BinaryKey="MyCertificate.Binary"
StoreLocation="localMachine"
PFXPassword="$(var.PfxPassword)" />
<?else?>
<iis:Certificate
Id="My.Certificate"
StoreName="root"
Overwrite="yes"
Name="My Web Site$(var.ConfigSuffix)"
Request="no"
BinaryKey="MyCertificate.Binary"
StoreLocation="localMachine" />
<?endif?>
I have also tried replacing "$(var.PfxPassword)" with "[PFXPASSWORD]" (having defined this elsewhere), and the actual password in plain text. In every case, installation fails with the following log snippet:
Action start 12:29:02: InstallCertificates.
InstallCertificates: Error 0x80070056: Failed to open PFX file.
InstallCertificates: Error 0x80070056: Failed to get SHA1 hash of certificate.
InstallCertificates: Error 0x80070056: Failed to resolve certificate: LinnRecords.Certificate
CustomAction InstallCertificates returned actual error code 1603 (note this may not be 100% accurate if translation happened inside sandbox)
Action ended 12:29:02: InstallCertificates. Return value 3.
I believe error 0x80070056 indicates an incorrect password, however I have used the Get-PfxCertificate in PowerShell to verify that the password I am using is correct.
For all configurations where the PFX file does not use a password, the installation works without issue.

Looking at a similar problem elsewhere on the internet, it looks like return code 3 is a "File not found" problem. Are you sure the correct pfx file is being included?

Related

signtool Error: Store::ImportCertObject() failed." (-2146885630/0x80092002)

I am running SignTool with the following arguments and keep getting the same failure.
D:\Sectigo-Signmycode>"C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64\signtool.exe" ^
sign /debug /fd SHA256 ^
/f keyfile.pfx /p password ^
/td SHA256 ^
/a MyExecutable.exe
SignTool Error: An unexpected internal error has occurred.
Error information: "Error: Store::ImportCertObject() failed." (-2146885630/0x80092002)
Error lookup returns "An error occurred during encode or decode operation". Windows 10 system.
I've tried SHA384 with same results. Passing invalid arguments gives the standard expected errors. However, and invalid password gives the above error. Numerous argument combinations have been tried.
The Security Certificate has only just been acquired.
Generation of the keyfile.pfx with correct password has been triple checked.
/debug has no effect.
Any ideas and/or help would be appreciated.
I had the exact same problem. Code-signing cert obtained from Sectigo via SignMyCode.com ... the problem was not with any of the signtool paramaters rather that SignMyCode.com gave me the wrong instructions to convert the .crt file(s) and .key file into a .pfx file. If you are using an online tool to create your .pfx file then you might have the same problem.
They initially advised I use the SSL Tools site which does not work to create valid .pfx files (ie resulting in the 0x80092002 error) ... when I went back to them and challenged this, they then said to use SSL Shopper. I created a .pfx file using this site and it worked perfectly first time.
I appreciate you may not be using any online tool to create your .pfx file (or you might have been provided with a .pfx file directly), but if you are, try the second link above.

NXLog with HTTPS: How to configure SSL and certificate?

I'm trying to use NXLog to post to a service in https.
Unfortunately, I keep receiving this error for every post attempts:
2018-12-19 09:11:14 ERROR SSL certificate verification failed: unable to get local issuer certificate (err: 20)
The service we are trying to reach is an HTTPS endpoint with a "Let's encrypt" certificate. I have no problem posting to the endpoint with tools like Postman. But NXLog keeps complaining.
I tried to play with the multiple options of the https module but since I don't really understand what they are and the documentation is not very helpful, I need help.
I tried to put HTTPSAllowUntrusted to TRUE but it doesn't change anything. Also tried to provide .pem file from mozilla and various source in HTTPSCADir and HTTPSCAFile but that doesn't change anything too.
Here is my latest .conf file attemps. Any help to be able to configure SSL would be welcome.
Panic Soft
#NoFreeOnExit TRUE
define ROOT C:\Program Files (x86)\nxlog
define CERTDIR %ROOT%\cert
define CONFDIR %ROOT%\conf
define LOGDIR %ROOT%\data
define LOGFILE %LOGDIR%\nxlog.log
LogFile %LOGFILE%
Moduledir %ROOT%\modules
CacheDir %ROOT%\data
Pidfile %ROOT%\data\nxlog.pid
SpoolDir %ROOT%\data
<Extension _syslog>
Module xm_syslog
</Extension>
<Extension _charconv>
Module xm_charconv
AutodetectCharsets iso8859-2, utf-8, utf-16, utf-32
</Extension>
<Extension csv>
Module xm_csv
Fields $contentName, $deviceName, $startTime, $endTime, $contentId, $deviceId
FieldTypes string, string, string, string, string, string
Delimiter ,
</Extension>
<Extension exec>
Module xm_exec
</Extension>
<Extension json>
Module xm_json
</Extension>
<Input in>
Module im_file
File "C:\\MagicInfo Premium\\runtime\\upload\\pop\\report\\*W*.csv"
Exec csv->parse_csv(); to_json();
</Input>
<Output http>
Module om_http
URL https://my-service.com/api/v1/proof-of-play-log/
HTTPSCAFile %CERTDIR%/cacert.pem
ContentType application/json
</Output>
<Route 1>
Path in => http
</Route>
To summarize: What .pem file do I need and what parameter needs to be set to do a simple post to an https endpoint that has a "Let's encrypt" certificate.
EDIT
Finally, I realised NXLog is completely buggy and badly coded so we changed to another solution...
The Intermediates May Be Missing
This is rare and may not be the solution to your problem, but it is a solution to some problems with exactly the same symptoms.
The untrusted very option may be failing because it may allow untrusted cert chains, but not orphaned / incomplete chains (which is slightly different). Though, on second thought, that’s probably not possible to distinguish...
But if it is the case, the extra certa you’d want to include are the intermediates listed in the “active” and “backup” sections at https://letsencrypt.org/certificates/

Get Nuget to pass a client certificate to a private ProGet server using SSL

I have a ProGet server that currently uses SSL and requires a client certificate in order to communicate with it. We would like to be able to use this server directly from the command line or within the Visual Studio package manager.
When accessed via a browser there are no issues with viewing the repository. When using nuget.exe on the command line the result is 403 Forbidden. I have used Fiddler to monitor the request and it highlights that the server is asking for a client certificate, Fiddler allows you to inject the required certificate and the nuget request is then successful.
Is it possible to provide a client certificate when using NuGet:
nuget install PackageName -Source https://myhost -Cert ???
Or with a setup like this we are going to have to fall back to using an API key to gain access?
Are we able to provide the certificate when using Visual Studio?
Starting from NuGet 5.7.2 you can use client-cert feature.
Configuration example:
<configuration>
...
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
<add key="Contoso" value="https://contoso.com/packages/" />
<add key="Example" value="https://example.com/bar/packages/" />
</packageSources>
...
<clientCertificates>
<storeCert packageSource="Contoso"
storeLocation="currentUser"
storeName="my"
findBy="thumbprint"
findValue="4894671ae5aa84840cc1079e89e82d426bc24ec6" />
<fileCert packageSource="Example"
path=".\certificate.pfx"
password="..." />
<fileCert packageSource="Bar"
path=".\certificate.pfx"
clearTextPassword="..." />
</clientCertificates>
...
</configuration>
Also you can use nuget client-certs CLI command for configuration.
I have realised that some years later I never posted the answer to this issue. In order to get NuGet to use certificates the certificate had to be added to the Credential Manager in Windows as a certificate based credential. NuGet then automatically picked this up when communicating with a matching URL.

Certificate Detection/Installation with WiX Installer

Using WiX, is there a way to detect if a Certificate is installed on a machine? Is the only option you have to run a custom action with C# to detect if the certificate is installed, or is there a built in way with WiX to do it. I know how to install a certificate with WiX, but there needs to be some custom logic to detect if it already exists.
For example...
Our installer is a Per-User install, which means we don't have write access to the local-machine certificate store (although we do have read access). I have the following component in my .wxs file that adds the certificate to the User Certificates store:
<Component Id="C__IntermediateCert" Guid="{GUID_HERE}" Permanent="no" >
<iis:Certificate Id="_IntermediateCert" BinaryKey="B__IntermediateCert" StoreName="ca" Overwrite="no"
StoreLocation="currentUser" Name="Intermediate Cert Name" Request="no" />
</Component>
The problem is that this line will fail if there is already a certificate with this name in the local machine certificate store, even though we specified overwrite=no. There is an installer error raised and the user cannot continue the installation.
So the workaround I want to implement is to first look to see if the certificate is installed on the machine (either in local machine or user) and skip the component if it is already installed. However, it doesn't appear there is anyway to just search for the certificate (like there is for files/directories).
Any suggestions or help with how to either search for the certificate, or point out what I am doing wrong in the certificate creation (to properly ignore if it is already installed) would be greatly appreciated!
EDIT: (with correct solution)
Adding some information about a workaround I tried, and is now working. I ended up creating a C# custom action that should check if the certificate exists
See here:
public static ActionResult CheckForExistingCertificate(Session session)
{
session.Log("Starting CheckForExistingCertificate");
try
{
session.Log("***** Beginning LocalMachine Certificate Store Search...");
X509Store lmStore = new X509Store(StoreName.CertificateAuthority, StoreLocation.LocalMachine);
lmStore.Open(OpenFlags.ReadOnly);
session.Log("***** lmStore.Certificates.Count = " + lmStore.Certificates.Count);
foreach(X509Certificate2 cert in lmStore.Certificates)
{
session.Log("lmCertificate Listing : " + cert.FriendlyName);
if (cert.FriendlyName == "Intermediate Cert Name")
{
session["INTERMEDIATECERTIFICATEALREADYINSTALLED"] = "TRUE";
}
}
session.Log("***** Beginning CurrentUser Certificate Store Search...");
X509Store cuStore = new X509Store(StoreName.CertificateAuthority, StoreLocation.CurrentUser);
cuStore.Open(OpenFlags.ReadOnly);
session.Log("***** cuStore.Certificates.Count = " + cuStore.Certificates.Count);
foreach (X509Certificate2 cert in cuStore.Certificates)
{
session.Log("cuCertificate Listing : " + cert.FriendlyName);
if (cert.FriendlyName == "Intermediate Cert Name")
{
session["INTERMEDIATECERTIFICATEALREADYINSTALLED"] = "TRUE";
}
}
}
catch
{
session.Log("CheckForExistingCertificate - in catch");
}
session.Log("Ending CheckForExistingCertificate - end of function");
return ActionResult.Success;
}
Interesting, I hit the exact same bug last week. I was really up against a deadline so I just wrote a custom action to delete the certificate if it exists and the component is being reinstalled. But yes, I believe this is a WiX 3.8 bug as If overwrite=no it shouldn't cause a problem.
In my case we were distributing a cert via group policy and via an MSI to ensure we had as close to 100% coverage as possible. The MSI worked and the GPO worked but then the MSI failed after the GPO was applied. I delete the GPO loaded cert, load mine and then when you do a GPUPDATE -FORCE you end up with two copies of the cert but with no obvious negative side effects.

App.config connection string Protection error

I am running into an issue I had before; can't find my reference on how to solve it.
Here is the issue. We encrypt the connection strings section in the app.config for our client application using code below:
config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)
If config.ConnectionStrings.SectionInformation.IsProtected = False Then
config.ConnectionStrings.SectionInformation.ProtectSection(Nothing)
' We must save the changes to the configuration file.'
config.Save(ConfigurationSaveMode.Modified, True)
End If
The issue is we had a salesperson leave. The old laptop is going to a new salesperson and under the new user's login, when it tries to to do this we get an error. The error is:
Unhandled Exception: System.Configuration.ConfigurationErrorsException:
An error occurred executing the configuration section handler for connectionStrings. ---> System.Configuration.ConfigurationErrorsException: Failed to encrypt the section 'connectionStrings' using provider 'RsaProtectedConfigurationProvider'.
Error message from the provider: Object already exists.
---> System.Security.Cryptography.CryptographicException: Object already exists
http://blogs.msdn.com/mosharaf/archive/2005/11/17/protectedConfiguration.aspx#1657603
copy and paste :D
Monday, February 12, 2007 12:15 AM by Naica
re: Encrypting configuration files using protected configuration
Here is a list of all steps I've done to encrypt two sections on my PC and then deploy it to the WebServer. Maybe it will help someone...:
To create a machine-level RSA key container
aspnet_regiis -pc "DataProtectionConfigurationProviderKeys" -exp
Add this to web.config before connectionStrings section:
<add name="DataProtectionConfigurationProvider"
type="System.Configuration.RsaProtectedConfigurationProvider, System.Configuration, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a,
processorArchitecture=MSIL"
keyContainerName="DataProtectionConfigurationProviderKeys"
useMachineContainer="true" />
Do not miss the <clear /> from above! Important when playing with encrypting/decrypting many times
Check to have this at the top of Web.Config file. If missing add it:
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
Save and close Web.Config file in VS (very important!)
In Command Prompt (my local PC) window go to:
C:\WINNT\Microsoft.NET\Framework\v2.0.50727
Encrypt: (Be aware to Change physical path for your App, or use -app option and give the name o virtual directory for app! Because I used VS on my PC I preferred the bellow option. The path is the path to Web.config file)
aspnet_regiis -pef "connectionStrings" "c:\Bla\Bla\Bla" -prov "DataProtectionConfigurationProvider"
aspnet_regiis -pef "system.web/membership" "c:\Bla\Bla\Bla" -prov "DataProtectionConfigurationProvider"
To Decrypt (if needed only!):
aspnet_regiis -pdf "connectionStrings" "c:\Bla\Bla\Bla"
aspnet_regiis -pdf "system.web/membership" "c:\Bla\Bla\Bla"
Delete Keys Container (if needed only!)
aspnet_regiis -pz "DataProtectionConfigurationProviderKeys"
Save the above key to xml file in order to export it from your local PC to the WebServer (UAT or Production)
aspnet_regiis -px "DataProtectionConfigurationProviderKeys" \temp\mykeyfile.xml -pri
Import the key container on WebServer servers:
aspnet_regiis -pi "DataProtectionConfigurationProviderKeys" \temp\mykeyfile.xml
Grant access to the key on the web server
aspnet_regiis -pa "DataProtectionConfigurationProviderKeys" "DOMAIN\User"
See in IIS the ASP.NET user or use:
Response.Write(System.Security.Principal.WindowsIdentity.GetCurrent().Name
Remove Grant access to the key on the web server (Only if required!)
aspnet_regiis -pr "DataProtectionConfigurationProviderKeys" "Domain\User"
Copy and Paste to WebServer the encrypted Web.config file.
I found a more elegant solution that in my original answer to myself. I found if I just logged in as th euser who orignally installed the application and caused the config file connectionstrings to be encrypted and go to the .net framework directory in a commadn prompt and run
aspnet_regiis -pa "NetFrameworkConfigurationKey" "{domain}\{user}"
it gave the other user permission to access the RSA encryption key container and it then works for the other user(s).
Just wanted to add it here as I thought I had blogged this issue on our dev blog but found it here, so in case I need to look it up again it will be here. Will add link to our dev blog point at this thread as well.
So I did get it working.
removed old users account from laptop
reset app.config to have section not protected
removed key file from all users machine keys
ran app and allowed it to protect the section
But all this did was get it working for this user.
NOW I need to know what I have to do to change the code to protect the section so that multiple users on a PC can use the application. Virtual PC here I come (well after vacation to WDW tomorrow through next Wednesday)!
any advice to help pointing me in right direction, as I am not very experienced in this RSA encryption type stuff.
Sounds like a permissions issue. The (new) user in question has write permissions to the app.config file? Was the previous user a local admin or power user that could have masked this problem?