How should I sign a CSR using a signature created in HSM, in C# .NET Core? - encryption

I'm exhausted after looking for an answer for 3 days. I don't know if my suggested flow is wrong or my Google skills have really deteriorated.
My API needs to create a valid certificate from a CSR it received, by signing it with a private key that exists ONLY inside an HSM-like service (Azure KeyVault), which unfortunately doesn't offer Certificate Authority functions BUT does offer signing data with a key that exists there. My CA certificate's private key is stored in the HSM. I'm using ECDSA.
My suggested flow:
Client generates Key Pair + CSR and sends CSR to API
API creates a certificate from the CSR
API asks HSM to sign the CSR data and receives back a signature
API appends the signature to the certificate and returns a signed (and including CA in chain) certificate to the Client
I'm using C# .NET Core and would like to keep it cross-platform (as it runs in Linux containers), so I have to keep it as native as possible or using Bouncy Castle (which I'm still not sure if runs in Linux .NET Core).
I really appreciate your help!

I had faced a similar issue and found a solution. You'll have to use the PKCS11Interop.X509Store library.
The solution uses dotnet core native System.Security.Cryptography.X509Certificates.CertificateRequest::Create method
for generating a certificate.
As per the docs:
Pkcs11Interop is managed library written in C# that brings the
full power of PKCS#11 API to the .NET environment
Pkcs11Interop.X509Store is managed library built on top of
Pkcs11Interop. It's main goal is to provide easy to use PKCS#11 based
read-only X.509 certificate store that can be easily integrated with
standard .NET ecosystem.
Till v0.3.0, implementation for issuing a certificate (i.e signing a CSR) is not available.
With minor modifications in the PKCS11Interop library, I was able to sign the CSR.
Mentioned in Issue #30, the code is now added in the PKCS11Interop.X509Store library version 0.4.0.
The below code is taken from test cases for BasicEcdsaCertificateRequestTest. Test cases for RSA CertificateRequest are also there.
// Load PKCS#11 based store
using (var pkcs11Store = new Pkcs11X509Store(SoftHsm2Manager.LibraryPath, SoftHsm2Manager.PinProvider))
{
// Find signing certificate (CA certificate)
Pkcs11X509Certificate pkcs11CertOfCertificateAuthority = Helpers.GetCertificate(pkcs11Store, SoftHsm2Manager.Token1Label, SoftHsm2Manager.Token1TestUserEcdsaLabel);
// Generate new key pair for end entity
ECDsa ecKeyPairOfEndEntity = ECDsa.Create(ECCurve.NamedCurves.nistP256);
// Define certificate request
CertificateRequest certificateRequest = new CertificateRequest(
new X500DistinguishedName("C=SK,L=Bratislava,CN=BasicEcdsaCertificateRequestTest"),
ecKeyPairOfEndEntity,
HashAlgorithmName.SHA256);
// Define certificate extensions
certificateRequest.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, true));
certificateRequest.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(certificateRequest.PublicKey, false));
certificateRequest.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature, false));
// Issue X.509 certificate for end entity
X509Certificate2 certificateOfEndEntity = certificateRequest.Create(
pkcs11CertOfCertificateAuthority.Info.ParsedCertificate.SubjectName,
X509SignatureGenerator.CreateForECDsa(pkcs11CertOfCertificateAuthority.GetECDsaPrivateKey()),
DateTimeOffset.UtcNow,
DateTimeOffset.UtcNow.AddDays(365),
new BigInteger(1).ToByteArray());
// Verify signature on X.509 certificate for end entity
Assert.IsTrue(CaCertSignedEndEntityCert(pkcs11CertOfCertificateAuthority.Info.ParsedCertificate.RawData, certificateOfEndEntity.RawData));
// Asociate end entity certificate with its private key
certificateOfEndEntity = certificateOfEndEntity.CopyWithPrivateKey(ecKeyPairOfEndEntity);
// Export end entity certificate to PKCS#12 file
string basePath = Helpers.GetBasePath();
string pkcs12FilePath = Path.Combine(basePath, "BasicEcdsaCertificateRequestTest.p12");
File.WriteAllBytes(pkcs12FilePath, certificateOfEndEntity.Export(X509ContentType.Pkcs12, "password"));
}
Hope this helps.

Related

Is it possible to have multiple keys in oiosaml keystore?

I am working on OIOSAML with ADFS 2.0. I need the IdP response to be signed as well as encrypted. Below is my understanding on how signing and encryption of SAML request and response works:
SP signs the request using its own certificate key (Key-1)
IdP verifies the request using SP's public key (Key-1)
IdP signs the response using its own certificate key (Key-2)
IdP encrypts the response assertion using certificate key provided by SP (Key-3)
SP verifies response using IdP's public key (Key-2)
SP decrypts the response assertion using its own private key (Key-3)
If I keep Key-1 and Key-3 same, everything works. As my keystore in OIOSAML has only one key.
But now I want to use separate keys for request signing and response encryption. It fails here.
Does OIOSAML support multiple keys in keystore?
If yes then how does it distinguish between signing and encryption keys?
This feature is available from OIOSAML release 3.

SAP .NET Connector, working with X509 certificates

We had a C# application connecting to SAP backend systemes using the SAPSSO technology. There has now been a need to replace this with X.509 certificates.
When using SAPSSO, the orginal code would make an HTTP call to the target system, and get a cookie containing the ticket to use:
response = (HttpWebResponse)request.GetResponse();
ticket = response.Cookies["MYSAPSSO2"].Value;
That ticket would then be passed to the RfcCustomDestination object to facilitate a secure connection:
prms.Add(RfcConfigParameters.SAPSSO2Ticket, ticket);
The problem is, I can change the enumerated value from SAPSSO2Ticket to X509Certificate,
prms.Add(RfcConfigParameters.X509Certificate, ticket);
but when I do this, no ticket can be returned from the response, since a MYSAPSSO2 cookie is no longer provided.
So how can I generate the needed ticket value for an X509 certificate?

Hosting WIF Identity Provider and generating self signed certificates for it

For my final year project I've developed an ASP.NET website and I've implemented a Single Sign On Login System using Windows Identity Foundation (in a similar manner to the tutorial shown here: http://www.primaryobjects.com/2013/08/08/using-single-sign-on-with-windows-identity-foundation-in-mvc-net )
This means that I currently have a 2 Websites, my Identity Provider Site and the site that uses the IP and contains most of the functionality.The IP uses X509 certificate to generate the token and for this I've been able so far to use a self signed certificate. This is the code that I've been using to retrieve the certificate from the local machine:
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
X509Certificate2Collection certificates = null;
store.Open(OpenFlags.ReadOnly);
try
{
certificates = store.Certificates;
var certs = certificates.OfType<X509Certificate2>().Where(x => x.SubjectName.Name.Equals(subjectName, StringComparison.OrdinalIgnoreCase)).ToList();
if (certs.Count == 0)
throw new ApplicationException(string.Format("No certificate was found for subject Name {0}", subjectName));
else if (certs.Count > 1)
throw new ApplicationException(string.Format("There are multiple certificates for subject Name {0}", subjectName));
return new X509Certificate2(certs[0]);
}
In order to be able to present my project I will be asked to host it on the web, but this will mean that I'll need a substitute for my self signed certificate.
I could use something like azure websites to host my websites but I wasn't able to find a solution so far that would allow me to generate a self signed certificate on a service like azure and retrieve it programatically.
Could you please suggest me a solution for this problem?
Ideally, you wouldn't have to create your own IDP. You could use something like ADFS.
Azure AD is an IDP and has its own certificates so you don't need to create any.
All you need is the metadata and you can find the URL under AppServices / Endpoints.
There's an example here but note that this uses WS-Fed OWIN not WIF. (WIF is somewhat old school).
To make your life easier, you can update your web.config programmatically by adding code to global.asax.
Or just move your whole solution to a VM in Azure.

WCF Message Level Security using Certificate (X.509) Message Signed and Encrypted

I have a common use case to implement a web service (WCF) and a web client which is consuming this web service. Both Client and Service are sending and receiving Signed and Encrypted messages (Message Level Security).
I can have multiple clients those are using my service, hence multiple client certificate need to be installed on Server where Service project is running.
I have installed 2 Certificates (Service Certificate and Client Certificate) in local machine store under personal and trusted root certification authorities.
makecert -sr LocalMachine -ss My -a sha1 -n "CN=WCFServer" -len 2048 -sky exchange -pe
makecert -sr LocalMachine -ss My -a sha1 -n "CN=WCFClient" -len 2048 -sky exchange -pe
Although Certificate give me error of "integrity of licence can not be guaranteed" but now i dont care about this issue.
Web Client need to Sign the request message through its own Private Key and Encrypt message through Service Certificate Public key.
Service receive the request and verify the signature of message through client Public Key and Decrypt the contents through own Private Key
Than process the request and create a response object.
Now Service must sign the response by own private key and encrypt the message through client public key.
Now client get Signed and Encrpted response. Now it verify the response through Service Public Key and Decrypt the message by its own private key.
This is whole Szenerio . I have installed both(Client and Service) X.509 Certificates on my local development machine. I am using wsHttpBinding and communication is working fine.
I am using [ServiceContract(ProtectionLevel=ProtectionLevel.EncryptAndSign)] for ServuceContract and [OperationContract(ProtectionLevel = ProtectionLevel.EncryptAndSign, IsOneWay = false)] for OperationContract.
I have following question:
do i need to Sign and Encrypt/Decrypt Request or Response message in my Code (once in client and once in service code) or Configurations in web.config on Service Project and Client project are enough to do all this stuff?
I go through following code project and its working fine.
http://www.codeproject.com/Articles/36683/simple-steps-to-enable-X-certificates-on-WCF
My Source code (Visual Studio Project) Including both certificates is available on Bitbucket for download here
Can any one tell me, do i need to do all this stuff in code or its done through my current configurations.
Thanks in advance.
i got following answer from MSDN forum.
do i need to Sign and Encrypt/Decrypt Request or Response message in my Code (once in client and once in service code) or Configurations in web.config on Service Project and Client project are enough to do all this stuff?
If we have configured the service to use the certificate authentication in the config file, then as you said all the response and request message will be Encrypted/Decrypted by the client certficate's private key/ public key and service certificate's private key/ public key. So in my mind it is enough to do all the stuff in the configure file.
For more information, please try to refer to the following articles:
Certificate authentication:
https://msdn.microsoft.com/en-us/library/ff648360.aspx .
Message and Transport Security:
https://msdn.microsoft.com/en-us/library/ff648863.aspx .
i have few more questions which may be any one can answer me.
I have multiple clients (external web applications ) which will access my service. do each client need to create their own certificate? client will deliver us certificate without private key which need to be install on Service Host server? is this a correct way?
Each client certificate need to be configured in web.config ?
I need to export my service certificate without private key and send to clients. clients must install and configure certificate on their application server? is this correct?
here i got another ver good answer (step by step guide) from MSDN Team.
https://social.msdn.microsoft.com/Forums/vstudio/en-US/a9d85e9f-6d35-425c-ac6d-b3cd883760e4/wcf-message-level-security-using-certificate-x509-message-signed-and-encrypted?forum=wcf&prof=required

WCF Certificate Authentication without installing on the Client

Our setup includes a WCF service and a number of clients written by us. Some of the clients include Silverlight applications, whereas others include Web and Windows applications.
I (think) I would like to authenticate clients based on X.509 certificates. Typically you would install a private key on the client to encrypt (aka digitaly sign) the messages. The server can the use the clients public key to de-crypt it to ensure the message has not been changed and prove the message is from who we expect (aka authenticated).
I dont want to install a certificate on a client machine. Its a hassel to deploy, and we cant really ask our clients to do it. I was speaking to someone the other day who sugested embeding the cert in a client assembly, reading it and using that. Is that possible?
It would be great if someone could point me to an example.
Thanks in advance,
David
Yes, you can load X509certificate2 by passing a certificate byte array with a password like
var certificate = new X509Certificate2(theByteArrary, "password");
To get the certificate byte array, you can simply copy paste the contents in .pfx file, which is a combination of .cer (public key) and .pvk (private key)
and then you can load this certificate on your client by doing:
var channelFactory = new ChannelFactory<IYourService>();
channelFactory.Credentials.ClientCertificate.Certificate =
clientCertificate;
If you use auto-generated client proxy, or you prefer configure the certificate via .config file then you might want to have a look at this from codeproject
Here is a suggestion. Could also be tweaked to use an embedded certificate.
http://www.codeproject.com/KB/WCF/wcfcertificates.aspx

Resources