SAML binding: Error getting X509Certificate2.PrivateKey on Azure - azure

The ITFoxtec Identity SAML 2.0 library contains a function to bind the request that extracts private key from signing certificate.
if(certificate is Saml2X509Certificate)
{
return (certificate as Saml2X509Certificate).GetRSAPrivateKey();
}
else
{
return certificate.GetRSAPrivateKey();
}
It works on local machine but on azure, it is giving the following error.
System.Security.Cryptography.CryptographicException: Invalid provider type specified.
at System.Security.Cryptography.Utils.CreateProvHandle(CspParameters parameters, Boolean
randomKeyContainer)
at System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters
parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandle& safeProvHandle, SafeKeyHandle&
safeKeyHandle)
at System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 dwKeySize, CspParameters
parameters, Boolean useDefaultKeySize)
at System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey()
at System.Security.Cryptography.X509Certificates.RSACertificateExtensions.GetRSAPrivateKey(X509Certificate2 certificate)
at ITfoxtec.Identity.Saml2.X509Certificate2Extensions.GetSamlRSAPrivateKey(X509Certificate2 certificate)
at ITfoxtec.Identity.Saml2.Saml2Binding1.BindInternal(Saml2Request saml2RequestResponse)
at ITfoxtec.Identity.Saml2.Saml2RedirectBinding.BindInternal(Saml2Request saml2RequestResponse, String messageName)
at ITfoxtec.Identity.Saml2.Saml2Binding1.Bind(Saml2Request saml2Request) .
Not sure whether it is saml library issue or azure configuration issue since it works on local machine.
I am using the certificate provided in the test webapp example. So, it doesn't look corrupted.
Does anyone know the reason behind this?

If you are using an Azure App Service, maybe the problem is that you need to make the SSL/TLS certificates private key accessible for your web application.
Adding an app setting named WEBSITE_LOAD_CERTIFICATES with its value set to the thumbprint of the certificate will make it accessible to your web application.

Related

How to read connection string from key vault for Service Bus?

Here is how I instantiate the client in my Configure method:
services.AddSingleton<ServiceBusClient>(x => new ServiceBusClient(configuration.GetSection("ServiceBus:ConnectionString").Value, serviceBusClientOptions));
And this how my appsettings looks like:
{
"ServiceBus:ConnectionString": "#Microsoft.KeyVault(VaultName=MyVaultName;SecretName=MySecretName)"
}
However, I am getting the following exception:
The connection string used for an Service Bus client must specify the Service Bus namespace host and either a Shared Access Key (both the name and value) OR a Shared Access Signature to be valid. (Parameter 'connectionString'
What am I missing here?
Have you created a managed identity for you application and added access policies such that your app can GET this secret value from key vault?
Check out the official documentaion for this here : https://learn.microsoft.com/en-us/azure/app-service/app-service-key-vault-references
Also on a side note, have you tried directly adding the secret value as the appsetting value instead of referencing it from KV and see if that worked? (if yes then definitely its a permissions issue and NOT a problem with your C# app code.

Unable to access my X509Certificate2's PrivateKey In Azure

I have my X509Certificate stored in a database (in byte[]) so that my application can retrieve the certificate and use it to sign my JWTs.
My x509Certificate is passed off a .pfx file that I generated on my machine, however now it sits in a database as a string of bytes.
My application works perfectly fine locally when I run it. The application can correctly create an instance of that X509Certificate2 and use it for my requirements, however the problem arises when I try to use it in my azurewebsites web application.
Basically I can not access the certificates' PrivateKey instance variable, I get an exception
System.Security.Cryptography.CryptographicException: Keyset does not exist
And I am re-instantiating the certificate with this
var cert = new X509Certificate2(myCertInBytes, myCertPass,
X509KeyStorageFlags.PersistKeySet |
X509KeyStorageFlags.MachineKeySet |
X509KeyStorageFlags.Exportable);
I am using ASPNET 5 rc1-update1. I have also tried running this on a different machine and it works fine, only have this issue when I publish to Azure. And to also add something else, This application was working when I was running the same project that was running using DNX version beta7
Any help appreciated.
The problem is the Azure Web Apps restricts access to the machines private key store, since it's a shared hosting environment, and you don't fully own the machine. As a workaround, you can load a cert. This blog post describes the best practice on how to do so:
https://azure.microsoft.com/en-us/blog/using-certificates-in-azure-websites-applications/
Please note that this only works for Basic Tier and above (not Free or Shared tier).
This can also be done from a .cer file as follows, however it should be noted that this is not best-practices since you're storing a secure credential with your code, in an insecure format.
public X509Certificate2 CertificateFromStrings(String certificateString64, String privateKeyXml)
{
try
{
var rsaCryptoServiceProvider = new RSACryptoServiceProvider();
rsaCryptoServiceProvider.FromXmlString(privateKeyXml);
var certificateBytes = Convert.FromBase64String(certificateString64);
var x509Certificate2 = new X509Certificate2(certificateBytes);
x509Certificate2.PrivateKey = rsaCryptoServiceProvider;
return x509Certificate2;
}
catch
{
return null;
}
}

Will a Windows Store app always disallow a self-signed certificate even if explicitly trusted?

I've seen both this and this — same problem, different question.
I'm trying to connect my Windows 8.1 Store app to an ASP.NET Web API web service, secured over HTTPS using a self-signed certificate. It's a proof-of-concept application that will end up on < 5 different machines and seen only internally, so I was planning to just install the certificate as trusted on each of the target machines.
When I try this on my development setup, both HttpClient APIs fail to establish the trust relationship when calling the service.
Windows.Web.Http.HttpClient exception: "The certificate authority is invalid or incorrect"
System.Net.Http.HttpClient exception: "The remote certificate is invalid according to the validation procedure."
My self-signed certificate (public-key-only .cer version) is installed in both the "User" and "Local Machine" Trusted Root Certification Authorities on the client. I'm really surprised that this isn't enough to get WinRT to trust it. Is there something I'm missing, or is there just no way to set up the trust relationship for a self-signed SSL certificate that will make HttpClient happy?
Details on my setup:
ASP.NET Web API
Azure web role running in Azure emulator
Cert issuer: 127.0.0.1
Cert subject: 127.0.0.1
Cert key: 2048-bit
Windows 8.1 Store application
Certificate (.cer file with public key only) installed in User\Trusted Root Certification Authorities
Certificate (.cer file with public key only) installed in Local Machine\Trusted Root Certification Authorities
Certificate (.cer file with public key only) added to Windows Store app manifest under "CA"
I am not asking for a workaround to configure HttpClient to accept self-signed or invalid certificates in general — I just want to configure a trust relationship with THIS one. Is this possible?
You should be able to find out what is the problem with the certificate by doing a request like this:
// using Windows.Web.Http;
private async void Foo()
{
HttpRequestMessage request = null;
try
{
request = new HttpRequestMessage(
HttpMethod.Get,
new Uri("https://localhost"));
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.SendRequestAsync(request);
}
catch (Exception ex)
{
// Something like: 'Untrusted, InvalidName, RevocationFailure'
Debug.WriteLine(String.Join(
", ",
request.TransportInformation.ServerCertificateErrors));
}
}
Using a HttpBaseProtocolFilter you can ignore certificate errors:
// using Windows.Web.Http;
// using Windows.Web.Http.Filters;
// using Windows.Security.Cryptography.Certificates;;
HttpBaseProtocolFilter filter = new HttpBaseProtocolFilter();
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName);
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.RevocationFailure);
HttpClient client = new HttpClient(filter);
HttpResponseMessage response = await client.SendRequestAsync(request);
The piece I was missing turned out to be that the certificate wasn't in the list of of IIS Server Certificates on my local machine!
Opening IIS Manager and checking out the Server Certificates section, I did find a 127.0.0.1 SSL certificate already set up by the Azure emulator:
CN = 127.0.0.1
O = TESTING ONLY
OU = Windows Azure DevFabric
However, my own self-signed certificate that I made outside of IIS, also with CN=127.0.0.1, was not in the list. I imported it, and now my Windows Store app's HttpClient connects happily (certificate warnings went away in Chrome and IE as well!)
If anyone can firm up the technical details on this, please comment — this fix feels a bit magical and I'm not sure I can pinpoint precisely why this worked. Possibly some confusion on my part between the two certs for 127.0.0.1, even though the thumbprint I had configured in my Azure project was always the one I was intending to use?

HttpRequest with Certificate fails in Azure Web-role

On my deployed azure web-role I try to send a request (GET) to a Web-Server that authorizes the request by the provided certificate of the requesting client.
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
var filepath = Path.GetTempPath();
string certpath = Path.Combine(filepath, "somecert.cer");
Trc.Information(string.Format("Certificate at {0} will be used", certpath));
X509Certificate cert = X509Certificate.CreateFromCertFile(certpath);
WebRequest request = WebRequest.Create(endPoint);
((HttpWebRequest)request).ProtocolVersion = HttpVersion.Version10;
((HttpWebRequest)request).IfModifiedSince = DateTime.Now;
((HttpWebRequest)request).AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
((HttpWebRequest)request).ClientCertificates.Add(cert);
The above code works perfectly in the azure-emulator but not when it is deployed. Then the call to GetResponse fails always.
System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.
at System.Net.HttpWebRequest.GetResponse()
at XYZ.Import.DataImport.OpenResponseStream(String endPoint)
I read through many of the existing discussion threads where using SecurityProtocolType.Ssl3 solved the problem but it does not in my case. Are there further debugging options considering that it is running on azure?
Update1
I tried all debugging steps that were suggested by Alexey. They are really helpfull but quite hard to execute properly on azure.
Here is with what I came up with after at least two hours.
I used the System.Net settings supplied by this post [1].
At first the output was not present in the expected folder. The file system settings on the folder need to be tweaked. Therefore the NT AUTHORITY\NETWORK SERVICE account should be allowed on the target folder.
After that the file didn't show up as expected because there seems to be a problem when only a app.config is supplied. See this thread [2]. So I provided a app.config a [ProjectAssembly].dll.config and a web.config with the content from the post [1].
To test if the Problem is related to User rights I tested with elevated rights and without like shown in post [3].
In advance I changed the Test-Project to execute in two modes. The first mode tries to load the public part in the *.cer file like shown in the code above.
The other version uses the private certificate that is loaded with this command
X509Certificate cert = new X509Certificate2(certpath, "MYPASSWORD", X509KeyStorageFlags.MachineKeySet);
As a result I gained the following insights.
When using the public part (.cer) it only works when the rights are elevated and the private cert is imported into the machine store
When using the private (.pfx) it only works if the private cert is imported into the machine store
The second setup with (.pfx) runs even without elevated rights
While debugging the CAPI2 log only had informations that had no direct relevance. The System.Net diagnostics from point one above contained this.
System.Net Information: 0 : [1756] SecureChannel#50346327 - Cannot find the certificate in either the LocalMachine store or the CurrentUser store.
[snip]
System.Net Error: 0 : [1756] Exception in HttpWebRequest#36963566:: - The request was aborted: Could not create SSL/TLS secure channel..
System.Net Error: 0 : [1756] Exception in HttpWebRequest#36963566::GetResponse - The request was aborted: Could not create SSL/TLS secure channel..
From this output and the changing situation when the elevated rights are used I would deduce that I should look further into the rights of the running web-role in combination with the certificate store.
[1] http://msdn.microsoft.com/de-de/library/ty48b824(v=vs.110).aspx
[2] Combined Azure web role and worker role project not seeing app.config when deployed
[3] http://blogs.msdn.com/b/farida/archive/2012/05/01/run-the-azure-worker-role-in-elevated-mode-to-register-httplistener.aspx
Remove SecurityProtocolType.Ssl3
Turn on CAPI2 log and check it for errors (on your local machine).
If there isn't error, then check location of CA and intermediate certificates.
Turn on system.net diagnostics and check this log for errors.
In this article describes how to find and turn on CAPI2 eventlog.
Hope this help.

Azure Autoscaling block cannot find certificate

I have the following situation: My azure application consists of 5 roles. One of those roles hosts the Autoscale block from Enterprise Library. This role is responsible for scaling the others up and down.
Now I followed the tutorial and added the Autoscale settings to the app.config and also added the services.xml and rules.xml.
The problem is that the autoscale logger (which works!) outputs this error over and over again:
Could not retrieve the instance count for hosted service with DNS
prefix 'myCloudApp'.
Microsoft.Practices.EnterpriseLibrary.WindowsAzure.Autoscaling.ServiceManagement.ServiceManagementClientException:
The service configuration could not be retrieved from Windows Azure
for hosted service with DNS prefix 'myCloudApp' in subscription id
'xxxxxxxxxxxxxxxxxx' and deployment slot
'Production'. --->
Microsoft.Practices.EnterpriseLibrary.WindowsAzure.Autoscaling.Security.CertificateException:
The certificate with thumbprint
'xxxxxxxxxxxxxxxxxxxxx' in store name 'My' and
store location 'LocalMachine' could not be found. at
Microsoft.Practices.EnterpriseLibrary.WindowsAzure.Autoscaling.Security.CertificateHelper.FindCertificate(StoreName
certificateStoreName, StoreLocation certificateStoreLocation, String
certificateThumbprint, Boolean withPrivateKey, Boolean validOnly) at
Microsoft.Practices.EnterpriseLibrary.WindowsAzure.Autoscaling.ServiceManagement.ServiceManagementClient.CreateFactory(StoreName
certificateStoreName, StoreLocation certificateStoreLocation, String
certificateThumbprint, Inspector inspector) at
Microsoft.Practices.EnterpriseLibrary.WindowsAzure.Autoscaling.ServiceManagement.ServiceManagementClient.CallOperation[TResult](Func2
call, StoreName certificateStoreName, StoreLocation
certificateStoreLocation, String certificateThumbprint, String
exceptionMessage, String& requestId) --- End of inner exception stack
trace --- at
Microsoft.Practices.EnterpriseLibrary.WindowsAzure.Autoscaling.ServiceManagement.ServiceManagementClient.CallOperation[TResult](Func2
call, StoreName certificateStoreName, StoreLocation
certificateStoreLocation, String certificateThumbprint, String
exceptionMessage, String& requestId) at
Microsoft.Practices.EnterpriseLibrary.WindowsAzure.Autoscaling.ServiceManagement.ServiceManagementClient.GetDeployment(String
hostedServiceDnsPrefix, String subscriptionId, DeploymentSlot
deploymentSlot, StoreName certificateStoreName, StoreLocation
certificateStoreLocation, String certificateThumbprint) at
Microsoft.Practices.EnterpriseLibrary.WindowsAzure.Autoscaling.ServiceManagement.ServiceManagementClientExtensions.GetDeployment(IServiceManagementClient
client, HostedService hostedService) at
Microsoft.Practices.EnterpriseLibrary.WindowsAzure.Autoscaling.DataPointsCollection.RoleInstanceCountDataPointsCollector.Collect(DateTimeOffset
collectionTime)
I replaced the actual thumbprint and subscription id with xxxxx.
I dont understand why it cannot access my cloud services. Do I need to do anything to this certificate?
Help is greatly appreciated!!
Did you actually upload the pfx (private key side) of the management certificate? This error indicates it cannot find the cert installed on the machine.
http://msdn.microsoft.com/en-us/library/windowsazure/gg465712.aspx

Resources