Reputation: 2786
I'm trying to implement Https Client Authentication in my application but I am having trouble finding any documentation on how to do it.
Looking through the MSDN documents I came up with this
// Certificate file in DER format (.cer or .p7b)
string CountriesFile = @"Assets\https-client.keystore.cer";
StorageFolder InstallationFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
StorageFile file = await InstallationFolder.GetFileAsync(CountriesFile);
// Read the file into a buffer
IBuffer buffer = await Windows.Storage.FileIO.ReadBufferAsync(file);
// Create the Certificate object
Certificate ClientCert = new Certificate(buffer);
HttpBaseProtocolFilter aHBPF = new HttpBaseProtocolFilter();
aHBPF.ClientCertificate = ClientCert;
// Create our http client and send the request.
HttpClient httpClient = new HttpClient(aHBPF);
HttpResponseMessage response = await httpClient.SendRequestAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead).AsTask(cts.Token);
I put this code together looking at the docs for HttpClient, HttpBaseProtocolFilter and Certificate. Making the assumption that I should have the certificate in the required format and read the file into the Certificate
class.
The above code doesn't work and throws this error
An exception of type 'System.ArgumentException' occurred in MyLib.DLL but was not handled in user code
WinRT information: The certificate specified is missing the required private key information.
I have tested my server set-up and it works with client auth through a browser, which leads me to two possible conclusions.
Certificate
class is constructed).Any one know how it should be done?
Upvotes: 2
Views: 1497
Reputation: 2786
It would appear that you have to install the certificate at a User level before you can effectively use it for client authentication within a Windows Store App
// Needs to be a PKCS12 (p12/pfx) file
string certPath = @"Assets\https-client.keystore.p12";
StorageFile file = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(certPath);
IBuffer buffer = await FileIO.ReadBufferAsync(file);
string certData = CryptographicBuffer.EncodeToBase64String(buffer);
// Will ask the user if they want this app to install the certificate if its not already installed.
await CertificateEnrollmentManager.UserCertificateEnrollmentManager.ImportPfxDataAsync(
certData,
"PASSWORD",
ExportOption.NotExportable,
KeyProtectionLevel.NoConsent,
InstallOptions.None,
"MyFriendlyName");
Now the certificate is installed, it will be available to us in the certificate store.
var certificate = await CertificateStores.FindAllAsync(new CertificateQuery() { FriendlyName = "MyFriendlyName" });
ClientCert = certificate.Single();
HttpBaseProtocolFilter aHBPF = new HttpBaseProtocolFilter();
aHBPF.ClientCertificate = ClientCert;
// Create our http client and send the request.
HttpClient httpClient = new HttpClient(aHBPF);
HttpResponseMessage response = await httpClient.SendRequestAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead).AsTask(cts.Token);
I would prefer to be able to make the certificate available to only the application and will update this answer if I find a way of doing it.
Upvotes: 2