6

I have a console app that is scheduled using Azure WebJobs. The execution always fails when attempting to read the private key of p12 certificate. Interestingly enough I can't catch the exception, I've had to use good old Console.WriteLine to debug.

Here is my snippet of code:

var certificate = new X509Certificate2(data, "notasecret", X509KeyStorageFlags.Exportable);

ServiceAccountCredential credential = new ServiceAccountCredential(
 new ServiceAccountCredential.Initializer(serviceAccountEmail)
 {
     Scopes = new[] { BigqueryService.Scope.Bigquery }
 }.FromCertificate(certificate));

Other posts have mention that the flags should be X509KeyStorageFlags.MachineKeySet but unfortunately that causes an error in the Google API. It requires the X509KeyStorageFlags.Exportable flag to be set.

Can anyone confirm that X509KeyStorageFlags.Exportable is usable on Azure Websites and WebJobs?

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
  • You may find this thread helpful: http://stackoverflow.com/questions/23330863/windows-azure-management-libraries-certification-error-on-web-job. – Gaurav Mantri Sep 16 '14 at 16:58
  • Yup, I saw that thread and blog post. The solution requires to set the `X509KeyStorageFlags.MachineKeySet` which is incompatible with the Google API SDK. – Perry Stathopoulos Sep 16 '14 at 17:25

2 Answers2

12

Using X509KeyStorageFlags.Exportable is not usable in IIS. I've tried it with Azure Webjobs, Azure Websites and IIS on my own virtual machine. It works in a development environment when using IISExpress because the process is running in the user's context.

So for it work in an IIS context (including Webjobs), it has to be set to MachineKeySet but the Google API will fail since it needs the private key.

The solution to my problem was actually pretty simple, create a console app that creates the X509Certificate2 object with Exportable flag set and then call ToXmlString(). Here is the snippet:

var certificate = new X509Certificate2(data, "notasecret", X509KeyStorageFlags.Exportable); var xml = certificate.PrivateKey.ToXmlString(true);

I then save the XML and use that XML to create an RSACryptoServiceProvider like this:

var rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(xmlKey);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
 {
  Scopes = new[] { BigqueryService.Scope.Bigquery },
  Key = rsa
 });

Hope this helps others.

  • I love you smart people that figures this stuff out. I had nothing to go on :) Thanks! – Olaj Sep 25 '14 at 14:33
  • You reference `data` when creating the X509Certificate2 object, are you pulling this out of the provided .p12 key somehow? – Phillip Copley Dec 30 '14 at 21:02
  • `data` refers to a byte array of the p12 certificate you get from Google Cloud project for OAuth credentials. Take a look at doc here: [https://cloud.google.com/bigquery/authorization#service-accounts-server](https://cloud.google.com/bigquery/authorization#service-accounts-server) – Perry Stathopoulos Dec 31 '14 at 21:57
  • Good Job! Works for me as well :) – Youp Bernoulli Mar 31 '15 at 12:26
  • This is amazing, but see answer by jmcnly which is much easier and solves this particular problem for Azure WebJobs etc – Steven Elliott Sep 23 '16 at 19:21
5

This solution worked in an Azure setting. However I also found one for my needs that was much simpler. Simply add additional Flags so everyone is happy...

 var certificate = new X509Certificate2(data,"notasecret",
                       X509KeyStorageFlags.MachineKeySet | 
                       X509KeyStorageFlags.PersistKeySet | 
                       X509KeyStorageFlags.Exportable);

I found this solution

Community
  • 1
  • 1
jmcnly
  • 51
  • 1
  • 1