Blazor Hosted WebAssembly application with Identity Server fails in production - iis

I am developping a Hosted Blazor WebAssembly application with Identity Server. It works perfectly in my development environment, but fails in a production environment.
To try and find the reason, I went back to the templates supplied with Visual Studio and got the same issue. So here are the details to replicate.
In VS 2022 (currently 17.4.4), create a new project.
Select the Blazor WebAssembly App template.
Select .NET 7.0 framework.
Select Individual Accounts for the Authentication type and check the ASP.NET Core Hosted option.
The application runs fine locally.
Before publishing it:
Create a self signed certificate with PowerShell and export it to a certificate.pfx file.
Edit the IdentityServer section in appsettings.json:
"IdentityServer": {
"key": {
"Type": "File",
"FilePath": "certificate.pfx",
"Password": "password"
},
"Clients": {
"BlazorWasmIdentityHosted.Client": {
"Profile": "IdentityServerSPA"
}
}
}
In Visual Studio, modify the certificate.pfx properties so that it is copied when publishing.
Modify the web.config file in the publish folder so that exception pages are displayed in the browser:
<aspNetCore ...>
<environmentVariables>
<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Development" />
</environmentVariables>
</aspNetCore>
I then get an error page as soon as I request the home page
CryptographicException: File not found.
System.Security.Cryptography.X509Certificates.CertificatePal.FilterPFXStore(ReadOnlySpan<byte> rawData, SafePasswordHandle password, PfxCertStoreFlags pfxCertStoreFlags)
InvalidOperationException: There was an error loading the certificate. Either the password is incorrect or the process does not have permisions to store the key in the Keyset 'DefaultKeySet'
Microsoft.AspNetCore.ApiAuthorization.IdentityServer.SigningKeysLoader.LoadFromFile(string path, string password, X509KeyStorageFlags keyStorageFlags)
As I am deploying to a hosting provider where I don't have a direct access to IIS, I suspect that I don't have the rights to add an item to a certificate store.
I tried deploying to IIS on my local machine, it runs fine.
So, my question is: Is there any other way to manage a signing key in this specific configuration: IIS on a shared hosting provider (managed with Plesk)?
The Microsoft documentation gives details about deploying to Azure (here), but I didn't find much on deploying to IIS in my situation.
Edited:
I finally think the issue was with lack of access rights for the IIS user on the hosting provider. Not sure if that can be fixed (depends on the provider), so I finally moved to Azure. Setting and deploying need some care, but at least it's well documented by Microsoft, and now it works for me.

I recently came across an article discussing common issues when dealing with X509Certificate2 object creation, handling private key material in application code. One of the common problems is certificate and private key handling inside .NET applications. Most of the problems for these use cases occur in web applications when certificate lookup/instantiation fails. For example, certificate reading works on a developer machine, but fails when the application is deployed to production. I want to share the content of this article with you, in order to avoid the article link from expiring, I quoted the content from the article in the answer, hoping to bring you some help.
There are two common deployment models for application certificates:
Persistent - certificate is installed in certificate store which is independent to application (such as Windows Certificate Store). The installed certificate is shared with any other application that runs under same security account.
In-app - The certificate is either embedded in the app itself or
stored as an external protected file. This includes PFX files,
keychains, Azure Key Vault, and many others.
Pros and Cons of the Persistent Deployment Model:
The benefit of the persistent deployment model is simplified
certificate management, which can be easily installed and managed
using external mechanisms such as certificate autoenrollment and
Certificate Lifecycle Manager (CLM). CLM makes it easy to manage
certificates in the certificate store without having to update or
redeploy applications every time certificates are renewed.
Of course the downside of this mode is that there is no certificate
isolation/protection between processes. When the application is
deleted, the certificate is not deleted and remains on the system.
Even if the certificate is deleted from persistent storage (Windows
certificate store), the private key is not necessarily deleted: case
of accidental deletion of user certificates. Another process under the
same security account or a computer administrator can easily access
the certificate and its private key material.
The in-app deployment model has the opposite characteristics of the persistent model.
The benefit of the in-app model is better certificate and private key
security. Private keys may not be shared with other applications
running under the same security account, and computer administrators
may be prevented from accessing private key material. The application
loads the certificate into memory only when necessary, and then
unloads the certificate and private key.
There is a parameter called password which is known only to authorized
applications and which provides private key isolation between
processes. Applications that do not know the password can’t access the
certificate and private key. Although the code looks secure, in fact
it is not in the current way. The problem is with default behavior of
the X509Certificate2 constructors that import certificate from PFX.
Using default constructors, such as X509Certificate2(String, String),
X509Certificate2(String, SecureString), X509Certificate2(Byte[],
String), X509Certificate2(Byte[], SecureString), private key is
silently copied and persisted on a system, this will introduce
security holes in working code. Any simple application/script can use
FileSystemWatcher to detect key file creation and immediately create a
copy of the key file.
To avoid this bad behavior, a constructor with three parameters must
be used. The third parameter is the X509KeyStorageFlags enumeration
type.
DefaultKeySet — copies private key to default store. It can be specified in PFX properties (user key set or machine key set). If none
specified in PFX, user key set is used. This is something you don’t
want to use, because it persists the key on a disc. And if PFX
specifies Machine Key Set and application doesn’t have local
administrator/system permissions, the call will fail with exception.
UserKeySet — forces private key copy to user profile regardless what is specified in PFX properties.
MachineKeySet — forces private key copy to local system profile. If application doesn’t have local administrator/system permissions,
the call will immediately fail.
Exportable — copies private key to default key set (see rules above) and makes private key exportable. This makes zero sense,
because application doesn’t need to have an access to private key
material. If the application require this, the application is simply
wrong. Instead, the application must deal with handles provided by
operating system. Nothing else.
UserProtected — this flag enables private key strong protection. This doesn’t work with any non-interactive applications, because raise
UI popups and require user input. And in web/background applications
the popup is raised in background sessions you cannot access.
PersistKeySet — is similar to DefaultKeySet with the exception that private key permanently persists on a disk even if you explicitly
release all handles.
EphemeralKeySet — the only flag that doesn’t copy private key material on a disk and the only that makes sense, because it does
exactly what we need — temporarily load the key from PFX and unload
when finished.
When loading a certificate with a private key from PFX or Azure Key Vault, you >should use the EphemeralKeySet enumeration value.
For more detailed content, you can get an in-depth understanding through the article link provided above.

Related

Imported TLS-certificate does not show up in App Service

I have a strange problem when importing a certificate from Azure Key vault to be used in an App Service. As you can see in the images below, it says the certificate is imported successfully but it does not show up as expected.
This have previous worked just fine for other app services and my custom domain matches the wildcard certificate that I am trying to use.
Any ideas what causes this strange behavior?
If you choose to upload or import a private certificate to App Service, your certificate must meet the following requirements:
Exported as a password-protected PFX file, encrypted using triple DES.
Contains private key at least 2048 bits long
Contains all intermediate certificates in the certificate chain
Some certificate authorities provide certificates in different formats, therefore before importing the certificate, make sure that they are either in .pem or .pfx format.
When you are importing the certificate, you need to ensure that the
key is included in the file itself. If you have the private key
separately in a different format, you would need to combine the key
with the certificate.
you can also refer https://www.huuhka.net/app-service-imported-ssl-certificate-from-another-subscription-kv/ if you have any failure messages while importing the key vault certificate
If you are using free managed certificate , you may check its pre-requisites to be fulfilled as free certificates come with few limitations , which can be referred from https://learn.microsoft.com/en-us/azure/app-service/configure-ssl-certificate?WT.mc_id=AZ-MVP-5003781#private-certificate-requirements
So, I made a workaround solution by setting an Managed Identity on my App Service giving it correct permissions to the keyvault. And then adding the application and correct permissions in Access policies for the keyvault.
After that the certificate showed up as expected when adding a binding on my App Service.
Seems you got the right solutions and might have encountered this issue due to your logged in user RBAC role.
When ever you use app service certificate it gets stored inside Azure Key vault and to use that key vault certificate/secret you need to have access policies to get the secret and set the secret.
More details at:
https://learn.microsoft.com/en-us/azure/key-vault/general/assign-access-policy-portal#:~:text=Assign%20an%20access%20policy%201%20In%20the%20Azure,the%20Principal%20selection%20pane.%20...%20More%20items...%20

What certificate store should I use to store a certificate for signing/encrypting JWT tokens?

I'm adding support for JWT tokens in my Web Application, and I have an X509 certificate which it needs for signing those tokens.
I have rejected the idea of using the same certificate we use for HTTPs (see Can I use the Private Key Certificate of Web App to sign JWT?).
I think a self signed certificate should do the trick, in fact I can't see any advantages of a web of trust in this scenario (that doesn't mean there aren't any, I just can't think of any).
The web application runs on a farm of web servers. My current plan is to generate a self signed cert and put the X509 certificate into the certificate store in Windows on each machine. Our IT department are checking, but they think they can roll that out to all the Web Servers in the farm using Group Policy. So this seems like a feasible plan.
The certificate store in windows looks pretty confusing to me. I think there are two options:
1) Put it in "My" store for the user under which the IIS App pool run. There are many app pools, so potentially the certificate will be in many stores.
2) Put it under the LocalMachine store, and then grant explicit access to the specific certificate for the IIS user(s).
3) Something else I can't think of.
Is there a "correct" place for these type of certs, and if so where is it?
The usual CertificateStore for signing certificates is the My store. I normally place them in LocalMachine location, but it is probably safer to put them in the certificate store for the Application Pool identity itself.
I would then give the Application Pool read-only access to this certificate only (right click certificate, then 'All Tasks' > 'Manage Private Keys', then add your Application Pool identity and give 'Read' permissions only.

Should I commit self-signed certificates to source control?

Let's say we generate a self-signed certificate for each of our customers. They're used in some part of the package/deploy pipeline and end up on the customer's local computers. They're used to connect to our web services.
Should we commit these certificates to source control? The repository is private and only accessible to coworkers. Should I leave them out for some security reason (even if that's just limiting access in case of accidental exposure, let alone malicious activity)?
If we leave them out, should we generate them as part of the package/deploy pipeline every time? Or stick them in some secure keystore and retrieve them?
This is a situation of trust and exposure. Do you trust those that have access to the repository? Bear in mind that most compromises come from insiders.
My thinking is this:
Don't store the deployed certificates at all. Generate them for those end systems. Sign them by a root certificate.
Configure your produce to trust connections made by certificates signed by that root. This way you can revoke certificates in mass if your root is compromised or selectively revoke endpoint certificates as necessary without revoking everything.
You can have your product reference the certificate from the system's certificate store using any public identifiers but don't store the private key.
Making the private key available should be a final deployment step with as minimal visibility as possible. Make it available to two or three users and use the platform's certificate management mechanisms for tying the public certificate to the private key.

Automated Code Signing - Protecting the private key

I want to automate the code signing of some ClickOnce deployment artifacts - application exe's and manifests. I am using signtool to accomplish this. In an attempt to make the private key available for signing and yet protect the certificate file containing the private key (.pfx file), my plan is to install the certificate into the local machine certificate store with a non-exportable key. (I am aware that there are ways of exporting the key even if it is marked non-exportable.) The machine is a continuous integration server that will be accessible to a select few. My hope was to set it up in such a way that any time the private key needed to be used, it would require the private key password to be entered. I would then set up an automated job (using Jenkins) which would require a build parameter that would collect the private key password. The Mask Passwords plugin would be used to mask the password while being entered and in the console output.
However, I've run into a couple of roadblocks. First of all, even though there is the "Enable strong private key protection. You will be prompted every time the private key is used by an application if you enable this option." when importing a certificate, it appears to be only available when importing it into the current user store, not the local machine store. Secondly, even if this option were available, the signtool tool doesn't provide an option for setting the password when signing using a certificate in a store. The password parameter, '/p', is only applicable when using a pfx file as the source of the private key ('/f' option). Given that, this doesn't appear to be a viable option. Note: Even if "Enable strong private key protection." is available for certificates in the machine store, my testing shows that attempting to use a certificate with this option enabled just pops up a dialog asking for permission to use it, which obviously wouldn't work for an automated job. I originally thought "prompting" meant it would ask for the password.
One other option I've considered is to create ACLs to secure the private key within a certificate store. This can be done by right clicking on the certificate and selecting All Tasks... | Manage Private Keys... dialog. This would restrict the private key usage to only those authorized. (Note: When a user without permissions on the private key attempts to use it for signing, they get the message "SignTool Error: No certificates were found that met all the given criteria.") However, I don't want to give access to the credentials being used by the Jenkins build service because then any build job would be able to sign code. I could create a job that would execute a script to run the signing command as a specific user. This would require taking the domain user name and password in as build parameters. I could do this using the Jenkins Mask Passwords plugin. I don't really like that, though, because I'm not comfortable that Mask Passwords is sufficient protection against exposing the domain credentials, which, if compromised, would give access to a lot more than just the private key.
If I abandon my original idea of storing the certificate in the machine store, there is the option of placing the certificate pfx file in an ACL secured folder on the build machine that only the build process and signing users have permissions on. Doing that would allow me to create a build job to use the contained private key while not exposing the file to others that have access to the machine. To use the private key, the build parameters would need to collect the private key password.
Finally, there is the option of using a smart card for storing the certificate but we've decided against that.
So, my question is, are there any other ways to do this that 1) protects the private key from being copied, 2) prevents the private key from being used by unauthorized users to sign code and 3), given the private key password is provided by an authorized user, makes the private key for signing by build service?
First of all I will try to answer your questions separately:
Protects the private key from being copied:Only the cryptographic hardware (smartcard or hsm) can really protect the key from being copied. Windows certificate store (even with non-exportable option as you correctly noted) or PKCS#12 (PFX) file provide only the false sense of protection.
Prevents the private key from being used by unauthorized users to sign code:IMO this requires user interaction such as entering password or PIN. If you pass the password as a parameter there is always a possibility that other processes would be able to gain it i.e. from process info, logs etc.
Given the private key password is provided by an authorized user, makes the private key for signing by build service:Cryptographic hardware (smartcard or hsm) accessible via CSP (windows certificate store) with interactively entered PIN should work with signtool without any problems.
I agree that the requirement of user interaction may not be exactly convenient for an automatic build service but you will probably have to choose between secure solution with user interaction and less secure solution without user interaction.
Convenient but less secure solution no. 1: It seems to me that you have already found an acceptable solution because you did not provide any of its disadvantages.
If I abandon my original idea of storing the certificate in the machine store, there is the option of placing the certificate pfx file in an ACL secured folder on the build machine that only the build process and signing users have permissions on. Doing that would allow me to create a build job to use the contained private key while not exposing the file to others that have access to the machine. To use the private key, the build parameters would need to collect the private key password.
However please note that PFX file can be copied undetectably not only from the live system but also from the backups.
Convenient but less secure solution no. 2: Store private key on a smartcard that does not require PIN to be entered and allow system access only to the trusted users. This would ensure that your private key cannot be copied while it would remain easily accessible for signtool. However it would probably require you to have two separate build servers - one without the smartcard accessible to all users and one with the smartcard accessible only to the trusted users.
Inconvenient secure solution: Store private key on a smartcard that requires PIN to be entered and require user interaction (entering of the PIN) during the build process.
You could also consider signing development builds with self-signed codesigning certificate in an automatic mode and signing public release builds with trusted codesigning certificate in manual mode.
The only option left that I see is to use HSM.
You could generate private key protected by operator card/cardset (for example Thales has this sort of HSMs). Operator cardset can be set with a quorum that specifies how many operators have to insert the card before the private key can be usable by application that requested use of this private key. Thales also has a CSP that supports this feature.
The problem might be that the CSP will invoke window to show user that a card has to be inserted (and optionaly password to that card entered). This problem might be solved when you run you build server under some user account with desktop that can be logged into. When you log in as this user and start the build server it has to request the use of private key (for example by signing some dummy file or something). Windows will pop up and operators (as many as required by the quorum) will one by one insert their cards and optionally enter their passwords. After all required cards have been inserted the key will be usable by your build server. Any other application (possibly started by other user) will go through same procedure to use that key. If your build server crashes (do build servers crash? ) you will go through the same procedure.
HSM have also tamper protection so the private key is IMHO safe in there. Sorry for talking about Thales HSMs only but I personally do not have experience with any other HSM.
It seems that relying on a password-protected PFX file, rather than the certificate store, is secure. Even without ACL protection on the hard drive folder where the PFX resides, no-one who takes the PFX file could use it to sign anything, unless they also had the password.
Then, set up a parameterized Jenkins "signing" job on that computer that fully encapsulates the PFX-password so that no-one can see it. (I am contemplating a script of some sort, Powershell maybe, converted to a black-box EXE.) Authorized Jenkins jobs could chain to the signing job to accomplish the signature. The EXE would log every time it was used, as an auditing feature. Just need to figure out how to prevent unauthorized use of the signing job...there must be a way to do that?

HttpWebRequest Client Certificate not working in IIS

I'm trying to create a WCF application hosted in IIS. This WCF App will call a third party website to download a CSV file. Third party website has provided a certificate to authenticate the WCF call. My development environment is,
-OS: Windows 2008R2
-Tools: Visual Studio 2010 (.Net 4.x)
During development I've no problem to make the calls using a HttpWebRequest, but after I deploy the same thing in IIS, it gives me the following error, even if I run the Visual Studio 2010 using IIS as dev server,
"\r\nCertificate information doesn't match login, connection denied."
The certificate during installation requires a password. I've installed it in "My User account" and "Computer account". It is also installed in IE. In all the installation it is installed in "Trusted Root Certification Authorities". But, still I'm getting the error message. I've given my code snippet below,
X509Certificate2 xc = new X509Certificate2(CertPath, GetCertificatePassword());
HttpWebRequest wc = (HttpWebRequest)WebRequest.Create(QryUrl);
wc.ClientCertificates.Add(xc);
Stream str = wc.GetResponse().GetResponseStream();
If someone can provide me any information, would be nice, thanks again,
This is just a guess: check that the user account that IIS runs under has access to the private key associated with the certificate.
If you use the MMC Certificates snap-in, select the certificate and then right-click -> All Tasks -> Manage Private Keys, and from there if you don't see the user account of IIS listed, you can add it there by clicking Add, and then in the dialog that comes up if for example you run IIS as Network Service, type "network service" (with the space) and click Check Names and then when you are back to Manage Private Keys you can set the security access.
I believe you only need to allow Read access to use the private key for a TLS connection.
You can set the access to the private key whether installed in Local Computer or Current User, but IIS won't have access to your Current User unless it runs as your user account.
Also, if it is a client certificate with a private key it almost certainly should go in the Personal store, and not in Trusted Root Certification Authorities. So try Local Computer, Personal, and give access to the private key to the account that IIS (or the application) runs under.

Resources