C
C#14mo ago
tftviking

❔ Load Certificate from Azure Key Vault as memorystream

I have a code that works perfect when testing it local and set my certificates as paths. When uploading it on Azure it do not work to use the path. My guess is that I have to upload the certificates on Key Vault and call the certificates from there. I'm using .NET Core Web App In the Nugget from Swish you can enter the certificate as direct path or as a stream. Do anyone have a solution how to fix this?
var clientCertificate = new SwishApi.Models.ClientCertificate()
{
CertificateFilePath = "Cert//Swish_Merchant_TestCertificate_1234679304.pfx",
Password = "swish"
};

string certificatePath = Environment.CurrentDirectory + "\\Cert\\Swish_Merchant_TestSigningCertificate_1234679304.pfx";
var payoutClient = new SwishApi.PayoutClient(clientCertificate, "https://eofvqci6optquip.m.pipedream.net", "1234", "1234679304", true, SwishApi.Environment.Emulator);

string instructionUUID = Guid.NewGuid().ToString("N").ToUpper();

// Anropa MakePayoutRequest med formulärvärden.
var response = payoutClient.MakePayoutRequest(PayoutTo, Personnummer, Amount, Message, instructionUUID, "7d70445ec8ef4d1e3a713427e973d097", new SwishApi.Models.ClientCertificate() { CertificateFilePath = certificatePath, Password = "swish" });
var clientCertificate = new SwishApi.Models.ClientCertificate()
{
CertificateFilePath = "Cert//Swish_Merchant_TestCertificate_1234679304.pfx",
Password = "swish"
};

string certificatePath = Environment.CurrentDirectory + "\\Cert\\Swish_Merchant_TestSigningCertificate_1234679304.pfx";
var payoutClient = new SwishApi.PayoutClient(clientCertificate, "https://eofvqci6optquip.m.pipedream.net", "1234", "1234679304", true, SwishApi.Environment.Emulator);

string instructionUUID = Guid.NewGuid().ToString("N").ToUpper();

// Anropa MakePayoutRequest med formulärvärden.
var response = payoutClient.MakePayoutRequest(PayoutTo, Personnummer, Amount, Message, instructionUUID, "7d70445ec8ef4d1e3a713427e973d097", new SwishApi.Models.ClientCertificate() { CertificateFilePath = certificatePath, Password = "swish" });
Have a look at this files : https://github.com/RickardPettersson/swish-api-csharp/blob/master/SwishApi/Models/ClientCertificate.cs https://github.com/RickardPettersson/swish-api-csharp/blob/master/SwishApi/PayoutClient.cs https://github.com/RickardPettersson/swish-api-csharp/issues/23
38 Replies
Pobiega
Pobiega14mo ago
Reading that issue, just set the UseMachineKeySet to true and pass a stream, and you're good to go?
tftviking
tftvikingOP14mo ago
The problem is that I dont know how to make the stream from Key Vault.
tftviking
tftvikingOP14mo ago
Yeah thats why I dont get it to work, but you think something like this?
var certificateOptions = new DownloadCertificateOptions("your-certificate-name");
var response = await keyVaultClient.DownloadCertificateAsync(certificateOptions);
var certificate = response.Value.Certificate;

using (MemoryStream certificateStream = new MemoryStream(certificate.RawData))
var certificateOptions = new DownloadCertificateOptions("your-certificate-name");
var response = await keyVaultClient.DownloadCertificateAsync(certificateOptions);
var certificate = response.Value.Certificate;

using (MemoryStream certificateStream = new MemoryStream(certificate.RawData))
Pobiega
Pobiega14mo ago
worth a try. unfortunately the documentation for RawData doesnt indicate if it includes the private key or not
tftviking
tftvikingOP14mo ago
And then make it two streams? one for each cert?
Pobiega
Pobiega14mo ago
yes remember that the streams cant be re-used either at least not without rewinding them first, but even then that might not be enough
tftviking
tftvikingOP14mo ago
Its only used once when you do the payout.
Pobiega
Pobiega14mo ago
okay, then thats less of an issue
tftviking
tftvikingOP14mo ago
its wrapped in a OnPost() So when you click the button it will run
Pobiega
Pobiega14mo ago
please dont download the certs each time the button is clicked lol download them at startup and keep them in memory as X509s
tftviking
tftvikingOP14mo ago
var certificateOptions1 = new DownloadCertificateOptions("certificate-name-1");
var response1 = await keyVaultClient.DownloadCertificateAsync(certificateOptions1);
var certificate1 = response1.Value.Certificate;

var certificateOptions2 = new DownloadCertificateOptions("certificate-name-2");
var response2 = await keyVaultClient.DownloadCertificateAsync(certificateOptions2);
var certificate2 = response2.Value.Certificate;

// Create MemoryStream instances for the certificates
using var certificateStream1 = new MemoryStream(certificate1.RawData);
using var certificateStream2 = new MemoryStream(certificate2.RawData);
var certificateOptions1 = new DownloadCertificateOptions("certificate-name-1");
var response1 = await keyVaultClient.DownloadCertificateAsync(certificateOptions1);
var certificate1 = response1.Value.Certificate;

var certificateOptions2 = new DownloadCertificateOptions("certificate-name-2");
var response2 = await keyVaultClient.DownloadCertificateAsync(certificateOptions2);
var certificate2 = response2.Value.Certificate;

// Create MemoryStream instances for the certificates
using var certificateStream1 = new MemoryStream(certificate1.RawData);
using var certificateStream2 = new MemoryStream(certificate2.RawData);
I get error on these
Severity Code Description Project File Line Suppression State
Error CS1061 'X509Certificate2' does not contain a definition for 'Certificate' and no accessible extension method 'Certificate' accepting a first argument of type 'X509Certificate2' could be found (are you missing a using directive or an assembly reference?) SwishPayoutMaster C:\Users\Alexander\source\repos\SwishPayoutMaster\SwishPayoutMaster\Pages\Payout.cshtml.cs 41 Active
Error CS1061 'X509Certificate2' does not contain a definition for 'Certificate' and no accessible extension method 'Certificate' accepting a first argument of type 'X509Certificate2' could be found (are you missing a using directive or an assembly reference?) SwishPayoutMaster C:\Users\Alexander\source\repos\SwishPayoutMaster\SwishPayoutMaster\Pages\Payout.cshtml.cs 45 Active
Severity Code Description Project File Line Suppression State
Error CS1061 'X509Certificate2' does not contain a definition for 'Certificate' and no accessible extension method 'Certificate' accepting a first argument of type 'X509Certificate2' could be found (are you missing a using directive or an assembly reference?) SwishPayoutMaster C:\Users\Alexander\source\repos\SwishPayoutMaster\SwishPayoutMaster\Pages\Payout.cshtml.cs 41 Active
Error CS1061 'X509Certificate2' does not contain a definition for 'Certificate' and no accessible extension method 'Certificate' accepting a first argument of type 'X509Certificate2' could be found (are you missing a using directive or an assembly reference?) SwishPayoutMaster C:\Users\Alexander\source\repos\SwishPayoutMaster\SwishPayoutMaster\Pages\Payout.cshtml.cs 45 Active
I just want to make it work before i move the logic
Pobiega
Pobiega14mo ago
well uh X509Certificate2 doesn't have a Certificate property. so.. dont try to access it? 😛
tftviking
tftvikingOP14mo ago
var certificateOptions1 = new DownloadCertificateOptions("TestCertificate");
var response1 = await keyVaultClient.DownloadCertificateAsync(certificateOptions1);
var certificate1 = response1.Value;

var certificateOptions2 = new DownloadCertificateOptions("TestSigningCertificate");
var response2 = await keyVaultClient.DownloadCertificateAsync(certificateOptions2);
var certificate2 = response2.Value;

using var certificateStream1 = new MemoryStream(certificate1.RawData);
using var certificateStream2 = new MemoryStream(certificate2.RawData);

// Omvandla MemoryStream till byte array
byte[] certificateData1 = certificateStream1.ToArray();
byte[] certificateData2 = certificateStream2.ToArray();

// Skapa X509Certificate2-objekt
var x509Certificate1 = new X509Certificate2(certificateData1);
var x509Certificate2 = new X509Certificate2(certificateData2);

var clientCertificate1 = new SwishApi.Models.ClientCertificate()
{
CertificateAsStream = new MemoryStream(x509Certificate1.Export(X509ContentType.Pkcs12, "swish")),
Password = "swish",
UseMachineKeySet = true
};

var clientCertificate2 = new SwishApi.Models.ClientCertificate()
{
CertificateAsStream = new MemoryStream(x509Certificate2.Export(X509ContentType.Pkcs12, "swish")),
Password = "swish",
UseMachineKeySet = true
};
var certificateOptions1 = new DownloadCertificateOptions("TestCertificate");
var response1 = await keyVaultClient.DownloadCertificateAsync(certificateOptions1);
var certificate1 = response1.Value;

var certificateOptions2 = new DownloadCertificateOptions("TestSigningCertificate");
var response2 = await keyVaultClient.DownloadCertificateAsync(certificateOptions2);
var certificate2 = response2.Value;

using var certificateStream1 = new MemoryStream(certificate1.RawData);
using var certificateStream2 = new MemoryStream(certificate2.RawData);

// Omvandla MemoryStream till byte array
byte[] certificateData1 = certificateStream1.ToArray();
byte[] certificateData2 = certificateStream2.ToArray();

// Skapa X509Certificate2-objekt
var x509Certificate1 = new X509Certificate2(certificateData1);
var x509Certificate2 = new X509Certificate2(certificateData2);

var clientCertificate1 = new SwishApi.Models.ClientCertificate()
{
CertificateAsStream = new MemoryStream(x509Certificate1.Export(X509ContentType.Pkcs12, "swish")),
Password = "swish",
UseMachineKeySet = true
};

var clientCertificate2 = new SwishApi.Models.ClientCertificate()
{
CertificateAsStream = new MemoryStream(x509Certificate2.Export(X509ContentType.Pkcs12, "swish")),
Password = "swish",
UseMachineKeySet = true
};
Stil not working, I can see in the breakpoints that I get the cert.
Pobiega
Pobiega14mo ago
dude
// Skapa X509Certificate2-objekt
var x509Certificate1 = new X509Certificate2(certificateData1);
var x509Certificate2 = new X509Certificate2(certificateData2);
// Skapa X509Certificate2-objekt
var x509Certificate1 = new X509Certificate2(certificateData1);
var x509Certificate2 = new X509Certificate2(certificateData2);
wtf var certificate2 = response2.Value; is already an X509Certificate2
tftviking
tftvikingOP14mo ago
xD Anyway with or without that I get System.NullReferenceException HResult=0x80004003 Message=Object reference not set to an instance of an object. Source=SwishApi StackTrace: at SwishApi.Models.PayoutRequestEnvelope.buildSignature(ClientCertificate signingCertificate)
Pobiega
Pobiega14mo ago
Not really going to dig through that project
tftviking
tftvikingOP14mo ago
Got it to work... First of all i loaded the public cert, not the secret.
Pobiega
Pobiega14mo ago
Right, the private key
tftviking
tftvikingOP14mo ago
// Ladda ner certifikaten som secrets
var secretBundle1 = await keyVaultClient.GetSecretAsync("TestCertificate");
var secretBundle2 = await keyVaultClient.GetSecretAsync("TestSigningCertificate");

// Skapa MemoryStream-objekt från secrets
using var certificateStream1 = new MemoryStream(Convert.FromBase64String(secretBundle1.Value.Value));
using var certificateStream2 = new MemoryStream(Convert.FromBase64String(secretBundle2.Value.Value));

var clientCertificate1 = new SwishApi.Models.ClientCertificate()
{
CertificateAsStream = certificateStream1
};

var clientCertificate2 = new SwishApi.Models.ClientCertificate()
{
CertificateAsStream = certificateStream2
};
// Ladda ner certifikaten som secrets
var secretBundle1 = await keyVaultClient.GetSecretAsync("TestCertificate");
var secretBundle2 = await keyVaultClient.GetSecretAsync("TestSigningCertificate");

// Skapa MemoryStream-objekt från secrets
using var certificateStream1 = new MemoryStream(Convert.FromBase64String(secretBundle1.Value.Value));
using var certificateStream2 = new MemoryStream(Convert.FromBase64String(secretBundle2.Value.Value));

var clientCertificate1 = new SwishApi.Models.ClientCertificate()
{
CertificateAsStream = certificateStream1
};

var clientCertificate2 = new SwishApi.Models.ClientCertificate()
{
CertificateAsStream = certificateStream2
};
Pobiega
Pobiega14mo ago
Okay thats slightly different. You base64 encoded your certs as secrets
tftviking
tftvikingOP14mo ago
Yes, i'm newbie. Im taking a 8 month course now as Developer
Pobiega
Pobiega14mo ago
You should be able to get a private key from the certs uploaded as certs itself, but this workaround works
tftviking
tftvikingOP14mo ago
Okey, the example was with filepath but i got access denied so i thought better to use Key Vault since im planning building a Saas solution for this since Swish it self dosent offer the service public. Just API
Pobiega
Pobiega14mo ago
.. you're making a Swish SAAS? Did you get approval from swish for this?
tftviking
tftvikingOP14mo ago
For companies to make payouts Are you Swedish?
Pobiega
Pobiega14mo ago
Yes English only on server.
tftviking
tftvikingOP14mo ago
There are services that almost do what I want already, so can't see that it should be any problems. Take a look at utbetalningar.nu
Pobiega
Pobiega14mo ago
Sure, but you'll need to contact swish and have this approved. You don't make a saas around another companies services without their approval they will just ban your cert and kill your app, so why not check with them first?
tftviking
tftvikingOP14mo ago
Its the customers certs. to use my service. When you request cert for Payout from your bank they ask if you have a solution to use the cert and for what purpose you want the cert.
Pobiega
Pobiega14mo ago
Ah okay.
tftviking
tftvikingOP14mo ago
Or you generate the certs in the swish panel but to get access
Pobiega
Pobiega14mo ago
I see
Denna tjänsten är inte i samarbete eller gjord av GetSwish AB.
alright, looks like utbetalningar.nu is in a similar position as yours
tftviking
tftvikingOP14mo ago
But this small service im building now is for a friend that buys and sell video games and other collectables like trading cards etc. When he buying from private individuals its easier to swish from the companys account rather than transfer money and swish from personal.
Pobiega
Pobiega14mo ago
sure also less illegal from a tax perspective 😄
tftviking
tftvikingOP14mo ago
Yes : But next problem. When I running from local it works now getting from Key Vault and do the memorystream without enter password.
var clientCertificate1 = new SwishApi.Models.ClientCertificate()
{
CertificateAsStream = certificateStream1
};
var clientCertificate1 = new SwishApi.Models.ClientCertificate()
{
CertificateAsStream = certificateStream1
};
When uploaded on Azure with no password I get
System.Security.Cryptography.CryptographicException: The system cannot find the file specified. at System.Security.Cryptography.X509Certificates.CertificatePal.FilterPFXStore(ReadOnlySpan`1 rawData, SafePasswordHandle password, PfxCertStoreFlags pfxCertStoreFlags) at System.Security.Cryptography.X509Certificates.CertificatePal.FromBlobOrFile(ReadOnlySpan`1 rawData, String fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(Byte[] rawData, String password, X509KeyStorageFlags keyStorageFlags) at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(Byte[] rawData, String password) at SwishApi.Models.PayoutRequestEnvelope.buildSignature(ClientCertificate signingCertificate) at SwishApi.PayoutClient.MakePayoutRequest(String payoutTo, String personalNumber, Decimal amount, String message, String instructionUUID, String signingCertificateSerialNumber, ClientCertificate signingCertificate)
System.Security.Cryptography.CryptographicException: The system cannot find the file specified. at System.Security.Cryptography.X509Certificates.CertificatePal.FilterPFXStore(ReadOnlySpan`1 rawData, SafePasswordHandle password, PfxCertStoreFlags pfxCertStoreFlags) at System.Security.Cryptography.X509Certificates.CertificatePal.FromBlobOrFile(ReadOnlySpan`1 rawData, String fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(Byte[] rawData, String password, X509KeyStorageFlags keyStorageFlags) at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(Byte[] rawData, String password) at SwishApi.Models.PayoutRequestEnvelope.buildSignature(ClientCertificate signingCertificate) at SwishApi.PayoutClient.MakePayoutRequest(String payoutTo, String personalNumber, Decimal amount, String message, String instructionUUID, String signingCertificateSerialNumber, ClientCertificate signingCertificate)
And with password
var clientCertificate1 = new SwishApi.Models.ClientCertificate()
{
CertificateAsStream = certificateStream1,
Password = "swish"
};
var clientCertificate1 = new SwishApi.Models.ClientCertificate()
{
CertificateAsStream = certificateStream1,
Password = "swish"
};
I get this
System.Security.Cryptography.CryptographicException: The specified network password is not correct. at System.Security.Cryptography.X509Certificates.CertificatePal.FilterPFXStore(ReadOnlySpan`1 rawData, SafePasswordHandle password, PfxCertStoreFlags pfxCertStoreFlags) at System.Security.Cryptography.X509Certificates.CertificatePal.FromBlobOrFile(ReadOnlySpan`1 rawData, String fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(Byte[] rawData, String password, X509KeyStorageFlags keyStorageFlags) at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(Byte[] rawData, String password) at SwishApi.Models.PayoutRequestEnvelope.buildSignature(ClientCertificate signingCertificate) at SwishApi.PayoutClient.MakePayoutRequest(String payoutTo, String personalNumber, Decimal amount, String message, String instructionUUID, String signingCertificateSerialNumber, ClientCertificate signingCertificate)
System.Security.Cryptography.CryptographicException: The specified network password is not correct. at System.Security.Cryptography.X509Certificates.CertificatePal.FilterPFXStore(ReadOnlySpan`1 rawData, SafePasswordHandle password, PfxCertStoreFlags pfxCertStoreFlags) at System.Security.Cryptography.X509Certificates.CertificatePal.FromBlobOrFile(ReadOnlySpan`1 rawData, String fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(Byte[] rawData, String password, X509KeyStorageFlags keyStorageFlags) at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(Byte[] rawData, String password) at SwishApi.Models.PayoutRequestEnvelope.buildSignature(ClientCertificate signingCertificate) at SwishApi.PayoutClient.MakePayoutRequest(String payoutTo, String personalNumber, Decimal amount, String message, String instructionUUID, String signingCertificateSerialNumber, ClientCertificate signingCertificate)
The same way with password as I used with path and then it worked. I have set permission for my app to get secrets in Key Vault
Pobiega
Pobiega14mo ago
¯\_(ツ)_/¯
Accord
Accord14mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server