How can I test a CNG key for exchangeable? - c#

I have taken a certificate:
X509Certificate2 x509 = store.Certificates.Find(X509FindType.FindBySubjectName, "CNGTestCert", false)[0];
and now I want to get the providertype parameter. But I cant do x509.PrivateKey.
In result of this I used var key = x509.GetRSAPrivateKey();. How can I get out of this key the ProviderType to decide the KeyNumber (looks like here: referencesource.microsoft.com). Or is there a easier way to test the private key for key function (key was created for signature or exchange)?

I found a way to check CNG certificate for exchangeable. If I read the private key of certificate by var privateKey = (cngCert.GetRSAPrivateKey() as RSACng).Key;, did I get the KeyUsage. The "KeyAgreement" flag marks the certificate for usage of secret agreement generation and key exchange.
var privateKey = (cngCert.GetRSAPrivateKey() as RSACng).Key;
if(privateKey.KeyUsage.HasFlag(CngKeyUsages.KeyAgreement))
{
//is for KeyExchange
}

Related

The private key is not present in the X.509 certificate from code bu available in certificate manager

So I am trying to use certificates to establish communication between my solution and a SOAP based service.
I have their certificate and my certificate installed into the certification store.
I have made sure that my certificate has a private key that corresponds to it:
Certificate has private key corresponding to it
However when loading my certificate in my code from the store I get the error "The private key is not present in the X.509 certificate."
I printed the following and can see that the Private Key is empty and ContainsPrivateKey == False
ClientCertificatePublicKey: System.Security.Cryptography.X509Certificates.PublicKey, ClientCertificatePrivateKey: , ContainsPrivateKey False
So far I have tried:
Setting the keystorageflags to:
X509KeyStorageFlags.MachineKeySet|
X509KeyStorageFlags.PersistKeySet|
X509KeyStorageFlags.Exportable
Setting Load User Profile to true in Applicaion Pool
Below is a snippet of how I read the certificate from the store
private byte[] ReadCertificate(string certificateThumbprint)
{
X509Store store = new X509Store("MY",StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection collection =
(X509Certificate2Collection)store.Certificates;
X509Certificate2Collection signingCert =
collection.Find(X509FindType.FindByThumbprint,
certificateThumbprint,false);
byte[] rawdata = signingCert[0].RawData;
store.Close();
return rawdata;
}
Does anybody have any idea on how I can fix this?
byte[] rawdata = signingCert[0].RawData;
actually, this returns only public part of the certificate, without private key reference. Instead, you shall consider to return entire X509Certificate2 object.

How can we create an AsymmetricSecurityKey?

How we can create AsymmetricSecurityKey in c#. Actually we are creating signing credentials with AsymetricSecurityKey here is our code:
// Define const Key this should be private secret key stored in some safe place
string key = "401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429090fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1";
// Create Security key using private key above:
// not that latest version of JWT using Microsoft namespace instead of System
var securityKey = new AsymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
// Also note that securityKey length should be >256b
// so you have to make sure that your private key has a proper length
//
var credentials = new Microsoft.IdentityModel.Tokens.SigningCredentials
(securityKey, SecurityAlgorithms.HmacSha256Signature);
You can generate public/private keys using:
public void GenerateRsaCryptoServiceProviderKey()
{
var rsaProvider = new RSACryptoServiceProvider(512);
SecurityKey key = new RsaSecurityKey(rsaProvider);
}
You should use RsaSha256 below:
var credentials = new Microsoft.IdentityModel.Tokens.SigningCredentials
(key, SecurityAlgorithms.RsaSha256);
Signing credentials with a AsymmetricSecurityKey in C# using a RSA private key:
// RSA Private Key Base64
var privateKey = #"...";
var privateKeyBuffer = new Span<byte>(new byte[privateKey.Length]);
Convert.TryFromBase64String(privateKey, privateKeyBuffer, out _);
// abstract class RSA : AsymmetricAlgorithm in namespace System.Security.Cryptography
var rsaPrivateKey = RSA.Create();
rsaPrivateKey.ImportRSAPrivateKey(privateKeyBuffer, out _);
// class RsaSecurityKey : AsymmetricSecurityKey in namespace Microsoft.IdentityModel.Tokens
var rsaSecurityKey = new RsaSecurityKey(rsaPrivateKey);
var signingCredentials = new SigningCredentials(rsaSecurityKey, SecurityAlgorithms.RsaSha256);
This is a possible solution on how to create AsymmetricSecurityKey object and a SigningCredentials object when we have a RSA private key (asymmetric key) in string format.
When you want to use asymmetric keys that are generated outside your application, you may need this additional steps to import an externally generated key.
Are you specifically looking for an AsymmetricSecurityKey?
I noticed that you are referencing the HM256 algorithm. That leads me to believe that you are looking for a SymmetricSecurityKey. Also, your approach seems very specific to using the HMAC alg.
To generate a SymmetricSecurityKey, you can try something like the following code:
// Define const Key this should be private secret key stored in some safe place
string key = "401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429090fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1";
// Create Security key using private key above:
// not that latest version of JWT using Microsoft namespace instead of System
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
// Also note that securityKey length should be >256b
// so you have to make sure that your private key has a proper length
//
var credentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
If you would like the a solution for using an RS256 alg (which will use a cert in pfx format), you can comment and I will do my best to give you an example of that too.
This creates security key from an RSA public key in F#.
let pem = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnzyis1ZjfNB0bBgKFMSvvkTtwlvBsaJq7S5wA+kzeVOVpVWwkWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHcaT92whREFpLv9cj5lTeJSibyr/Mrm/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIytvHWTxZYEcXLgAXFuUuaS3uF9gEiNQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0e+lf4s4OxQawWD79J9/5d3Ry0vbV3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWbV6L11BWkpzGXSW4Hv43qa+GSYOD2QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9MwIDAQAB"
let getPublicKey (pem: string) =
let publicKey = ReadOnlySpan<byte>(Convert.FromBase64String(pem))
let rsa = RSA.Create()
let mutable read = 0
rsa.ImportSubjectPublicKeyInfo(publicKey, &read)
new RsaSecurityKey(rsa)
getPublicKey pem

Unable to fetch private key from .net x509certificate2 object to bouncycastle AsymmetricCipherKeyPair

I was trying to get keypair for pkcs-7 signature an X509Certificate2 object from this code.
RSACryptoServiceProvider key = (RSACryptoServiceProvider)Cert.PrivateKey;
RSAParameters rsaparam = key.ExportParameters(true);
AsymmetricCipherKeyPair keypair = DotNetUtilities.GetRsaKeyPair(rsaparam);
This works fine if X509Certificate2 object is created using .pfx file like this
X509Certificate2 cert = new X509Certificate2(".pfx file path", "password");
it works fine.
but when the certificate is listed from certificate store like this
X509Certificate2 cert;
X509Store UserCertificateStore = new X509Store("My");
UserCertificateStore.Open(OpenFlags.ReadOnly);
var certificates = UserCertificateStore.Certificates;
foreach (var certificate in certificates)
{
if (certificate.Thumbprint==thumbprint)
{
cert=certificate;
break;
}
}
it throws an exception with the message - Key not valid for use in specified state.
after #Crypt32 answer tried using RSA method sign hash
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)cert.PrivateKey;
using (SHA256Managed sHA256 = new SHA256Managed())
{
byte[] hash = sHA256.ComputeHash(data);
return csp.SignHash(hash, CryptoConfig.MapNameToOID("SHA256"));
}
but the signature was not in PKCS#7 format
This is because BouncyCastle attempts to get raw key material (literally, export) from .NET object while actual key is not marked as exportable. In Windows systems, keys are stored in cryptographic service providers which control all key operations. When you need to perform a specific cryptographic operation, you are asking CSP to do a job and it does without having to expose key material to you. If the key was imported/generated in CSP as exportable, you can ask CSP to export key material. If this flag was not set, CSP won't give you the key.
I don't know how BouncyCastle works, but if it expects raw key material, then you need exportable private key in your certificate.
To answer the underlying question, "How do I make a PKCS#7 SignedData message signed with RSA+SHA-2-256?"
https://github.com/Microsoft/dotnet/blob/master/releases/net471/dotnet471-changes.md#bcl says that SHA-2-256 not only works in 4.7.1, but it's the default now:
Updated SignedXML and SignedCMS to use SHA256 as a default over SHA1. SHA1 may still be used by selected as a default by enabling a context switch. [397307, System.Security.dll, Bug]
On older frameworks it's possible via:
ContentInfo content = new ContentInfo(data);
SignedCms cms = new SignedCms(content);
CmsSigner signer = new CmsSigner(cert);
signer.DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1");
cms.ComputeSignature(signer);
return cms.Encode();
Where "2.16.840.1.101.3.4.2.1" is OID-ese for SHA-2-256.

c# Verify the certificate's signature using the nominated public key

i have 1x X509Certificate2 with a Publickey (x509certificate_1)
Now i created a new X509Certificate2 and try to Verify it.
Org.BouncyCastle.X509.X509Certificate x509certificate_11 = DotNetUtilities.FromX509Certificate(x509certificate_1);
Org.BouncyCastle.X509.X509Certificate x509certificate_22 = DotNetUtilities.FromX509Certificate(x509certificate_2);
x509certificate_22.Verify(x509certificate_11.GetPublicKey());
ERROR: Public key presented not for certificate signature
Can somebody explain me, how to verify my x509certificate_2 to x509certificate_1?

How can i import RSACryptoServiceProvider private key to bouncy castle

Currently, I am using the etoken (safenet), bouncy castle library and X509certificate2 to decrypt a p7m file.
I would like to decrypt the p7m byteArray through the Bouncy Castle library using a X509Ceritificate2 private key. I can retrieve the X509Ceritificate2 private key from the X509Store and the key is not null. I can utilize the private key when it is a RSACryptoServiceProvider object.
RSACryptoServiceProvider systemUserOnlyReadablePrivateKey = certificate.PrivateKey as RSACryptoServiceProvider;
However, when I tried to tranform the private key from RSACryptoServiceProvider object to other objects such as byte[] or AsymetricKeyParameter, An exception message "key not valid for use in specified state." has been shown.
AsymetricKeyParameter key = DotNetUtilities.GetKeyPair(cert.Privat‌​eKey).Private; //Exception prompt
Since the certificates are stored in the eToken and automatically added in the X509Store when eToken plugin into computer and certificates removed when the eToken plugged out, I can not set the certificates as exportable.
Does Bouncy Castle API support decryption by using X509Ceritificate2 private key?
How can I transform the key into other object so that I can decrypt by the Bouncy Castle API.
Thanks.
The following is my source code.
byte[] p7mByte = p7mByteArray; //p7m to byte array
cmsEnvelopedData = new CmsEnvelopedDataParser(p7mByteArray);
RecipientInformationStore recipientInformationStore = cmsEnvelopedData.GetRecipientInfos();
RecipientInformation recipientInformation = null;
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.MaxAllowed);
var certificates = store.Certificates;
foreach (var certificate in certificates)
{
if (certificate.PrivateKey != null)
{
RecipientID recipientId = new RecipientID();
recipientId.SerialNumber = certificate.SerialNumber;
recipientId.Issuer = certificate.IssuerDN;
recipientInformation = recipientInformationStore.GetFirstRecipient(recipientId);
RSACryptoServiceProvider systemUserOnlyReadablePrivateKey = certificate.PrivateKey as RSACryptoServiceProvider;
CspParameters cspParameters = new CspParameters(systemUserOnlyReadablePrivateKey.CspKeyContainerInfo.ProviderType, systemUserOnlyReadablePrivateKey.CspKeyContainerInfo.ProviderName, systemUserOnlyReadablePrivateKey.CspKeyContainerInfo.KeyContainerName)
{
Flags = CspProviderFlags.UseArchivableKey
};
RSACryptoServiceProvider csp = new RSACryptoServiceProvider(cspParameters);
csp = (RSACryptoServiceProvider)certificate.PrivateKey;
CmsTypedStream recData = null;
recData = recipientInformation.GetContentStream(DotNetUtilities.GetKeyPair(cert.Privat‌​eKey).Private); //Exception prompt
}
}

Categories

Resources