6

I want to create an Azure function (C# API Generic HTTP) method that uploads a file to an Office365 Sharepoint document library.

Because OneDrive API allows me to upload large files (using daemon process & certificate authentication), I have succeeded in achieving the goal with a C# Console Application.

The idea would be now to move the code into an Azure function. However, I receive an error during runtime of the function on the loading of the pfx-certificate.

public static async Task<bool> Run(HttpRequestMessage req, TraceWriter log)
{
   string certfile = System.IO.Path.Combine(Environment.ExpandEnvironmentVariable‌​s("%HOME%"), @"site\wwwroot\<functionname>\mykeyfile.pfx"); 

    X509Certificate2 cert = new X509Certificate2(certfile, "<myinsanepwd>");

    return true; //temporary 
}

The line X509Certificate2 cert = new X509Certificate2(certfile, ""); throws an Exception System.Security.Cryptography.CryptographicException: The system cannot find the file specified.

This is really strange because the file exists on the specified path (I checked using File.Exists() in the method :) ) Could this error have something to do with support.microsoft.com/en-us/kb/948154 ? How can I solve this?

Best regards, Jens

Janusz Nowak
  • 2,595
  • 1
  • 17
  • 36
Jens
  • 181
  • 1
  • 13

2 Answers2

16

Adding X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable to the constructor. This code works for me:

using System.Net;
using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
    string certfile = System.IO.Path.Combine(Environment.ExpandEnvironmentVariable‌​s("%HOME%"), @"site\wwwroot\HttpTriggerCSharp4\myCertFile.pfx");        
    log.Info(certfile); 
    log.Info(System.IO.File.Exists(certfile).ToString());
    X509Certificate2 cert = new X509Certificate2(certfile, "password", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);     
    log.Info(cert.Thumbprint);
Alexey Rodionov
  • 1,436
  • 6
  • 8
  • Great, this works indeed. Thanks alot for the help! P.S. I liked the other solution aswell and it did had the advantage of having the certificate already installed in the app service. – Jens Oct 26 '16 at 07:23
  • Could you explain why this difference exists for Azure functions? I tried to load the certificate from an in-memory stream. So it does exist. – Ramon de Klein Sep 13 '17 at 12:11
  • You're a life saver! I had `X509Certificate` instead of `X509Certificate2` and it wasn't working for me. So please make sure you are using `X509Certificate2`! – Felipe Cruz Feb 22 '18 at 12:51
4
  1. Upload your certificate through the portal: Function App Settings -> Go to App Service Settings -> SSL certificates -> Upload Certificate

  2. Once you have uploaded your certificate through the Azure portal you need to add an appsetting (also through the portal) called WEBSITE_LOAD_CERTIFICATES and set the value for this to the thumbprint of your uploaded certificate. This can be a comma separated list of multiple thumbprints if you want, or even * to load all your uploaded certificates

  3. Code:

    using System.Net;
    using System.Security.Cryptography;
    using System.Security.Cryptography.X509Certificates;
    
    public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
    {
        var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
        store.Open(OpenFlags.ReadOnly);
        var certs = store.Certificates.Find(X509FindType.FindByThumbprint, "Your thumb", false);
    
Alexey Rodionov
  • 1,436
  • 6
  • 8
  • Hi Alexey. Thank you for the fast response, however, I have added the certificate succesfully and added the appsetting with value of the thumbprint. When searching for the Thumbprint, I receive 0 certificates. I noticed that the .My store does not have any certificates :o – Jens Oct 25 '16 at 19:51
  • I use the Dynamic plan .. Has it something to do with the plan / billing? – Jens Oct 25 '16 at 20:03
  • 1
    [This](https://github.com/Azure/azure-webjobs-sdk-script/issues/1032) is what we found out, it's not working on Consumption mode. [Other thread](http://stackoverflow.com/questions/41013766/accessing-certificate-from-within-a-c-sharp-azure-function) – dave000 Dec 07 '16 at 15:54
  • As of 7/27/2017, I found that `X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable` does not work in Consumption mode, but this method with WEBSITE_LOAD_CERTIFICATES does indeed now work, they added support for it. Thanks for posting this! – Nicholas Piasecki Jul 27 '17 at 14:09