How to check is X509Certificate2 exportable or not - c#

var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
var certificates = store.Certificates.Find(
X509FindType.FindByThumbprint, thumbprint, false);
X509Certificate2 cert = certificates[0];
Now we have X509Certificate2 instance. How to check exportable private key or not? (preferably without trying to export explicitly)

Another approach I found here: How to determine whether an X509Certificate2 is exportable
X509Certificate2.PrivateKey Gets the AsymmetricAlgorithm object that represents the private key associated with a certificate.
The RSACryptoServiceProvider class is a AsymmetricAlgorithm
Then get the RSACryptoServiceProvider.CspKeyContainerInfo which is a CspKeyContainerInfo object that has a Exportable property that: Gets a value indicating whether a key can be exported from a key container.
Update: works. So, if you use RSA certificates, it is acceptable approach.

Looking at the reference source, the implementation of the Export method makes the following checks:
That the X509ContentType parameter is Cert, SerializedCert or Pfx.
When the content type is Pfx it makes a key container permission demand for both Export and Open permissions.
Beyond this, everything else happens via internal calls to the CLR, so it's much harder to say what demands are made of the caller. I can't observe a check in the source which tests for the exportable flag.
This is a scenario where I would suggest you attempt to perform the export and handle any exceptions as feedback; you cannot reasonably predict the outcome of the call with the information exposed by the certificate.

Use this method:
public static bool CheckCertificateIsExportable(X509Certificate2 certForCheck, X509ContentType certType)
{
try
{
certForCheck.Export(certType);
return true;
}
catch
{
return false;
}
}
How to use:
if (CheckCertificateIsExportable(certForCheck, X509ContentType.Pkcs12))
{
// Do...
}

Related

Import BouncyCastle X509Certificate + Private Key (RSA) into Windows Certificate Store

I've tried about everything to import a BouncyCastle-based X509Certificate instance with the associated private key (RsaPrivateCrtKeyParameters) via a .NET X509Certificate2 + an RSACryptoServiceProvider instances and saved it into a certificate store (.NET's X509Store, My/CurrentUser).
In the Certificate Store MMC snapin, it seems like there is a private key associated with the certificate, and I've verified that a new key container is created in the appropriate place on disk, but when I try to export the certificate, I get the dreaded "Note: The associated private key cannot be found. Only the certificate can be exported" message.
If I run certutil -user -repairstore my THUMBPRINT, I get the following error:
ERROR: Certificate public key does NOT match stored keyset
From the other information it spits out, I can clearly see that the public keys differ, and that the Algorithm Parameters equals "05 00" on the Certificate Public Key, but not on the Container Public Key.
In fact, I was not aware that there was a concept of a container public key, so I'm just very confused now. Does anyone have some working code for doing this?
I found the solution in Cabadam's answer here:
https://social.msdn.microsoft.com/Forums/vstudio/en-US/ad01b2eb-1890-431a-86ae-e5da0e02b5b0/cryptographicexception-key-does-not-exist-when-attempting-to-connect-to-remote-service
RSACryptoServiceProvider tempRcsp = (RSACryptoServiceProvider)DotNetUtilities.ToRSA((RsaPrivateCrtKeyParameters)keyPair.Private);
RSACryptoServiceProvider rcsp = new RSACryptoServiceProvider(new CspParameters(1, "Microsoft Strong Cryptographic Provider", new Guid().ToString(), new CryptoKeySecurity(), null));
rcsp.ImportCspBlob(tempRcsp.ExportCspBlob(true));
dotnetCertificate2.PrivateKey = rcsp;
// Save the certificate to the X509Store

How to check if a key already exists in container?

I'm building an application for secure messaging between multiple clients. In order to achieve that, I encrypt the message with AES, then I encrypt the AES key with the recipients public RSA key, then I send these two components (RSA-encrypted AES key and AES-encrypted message) to the recipient. The whole process works well and without any errors.
Now I ran into a problem and I'm wondering what would be the best practice: In order to persist the private and public key of one participent, I need to store the key pair. Saving it somewhere as an XML file is possible, but obviously not an option. So decided to use a key container as described here. Implementing the use of the container is quite easy, but how can I
Check if a specified container already exists?
Check if the key size matches a given value?
As far as I can see this is not possible, because the RSACryptoServiceProvider generates a new key if the container does not exist - without telling so. But I need to know if there is a previously stored key pair available or if a new one is created.
How can I fix that? Or is this a completely wrong approach?
Try this:
public static bool DoesKeyExists(string containerName)
{
var cspParams = new CspParameters
{
Flags = CspProviderFlags.UseExistingKey,
KeyContainerName = containerName
};
try
{
var provider = new RSACryptoServiceProvider(cspParams);
}
catch (Exception e)
{
return false;
}
return true;
}
similiar question: How to check if RSA key container exists in .NET

how to load password protected certificates from the X509Store?

I am building an ACS protected Azure WCF service that will require clients to authenticate via a certificate.
I would like the client (and the server) to load their respective password certs from the X509Store instead of from the file system.
I am using this code:
private static X509Certificate2 GetCertificate(string thumbprint)
{
var certStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
certStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certCollection = certStore.Certificates.Find(
X509FindType.FindByThumbprint,
thumbprint, false);
certStore.Close();
if (certCollection.Count == 0)
{
throw new System.Security.SecurityException(string.Format(CultureInfo.InvariantCulture, "No certificate was found for thumbprint {0}", thumbprint));
}
return certCollection[0];
}
Problem is, it's not loading the private key which it needs for authentication. I have tried to modify the return statement to this:
return new X509Certificate2(certCollection[0].Export(X509ContentType.Pfx, "password"));
However, this fails with a CryptographicException "The spcecified network password is incorrect".
Edit:
The .Export() method works properly if you don't pass the password argument in.
Any help on this?
When you export, the password you provide is the password you want to use for the exported file, it's not the password for the source certificate.
I'm not sure what you can do with X509Store and password-protected certs because the password should be supplied to the X509Certificate constructor and you get already-instantiated objects out of the store.
I think you can just get the raw data from the cert you want and construct a new one with the password you want. For example:
X509Certificate2 cert = new X509Certificate2(certCollection[0].GetRawCertData, password);
I would also suggest you try to use SecureString when dealing with passwords (but that's a different bag of worms...)
I used the Export without the 'password' parameter and it worked without issue.
When the cert was imported into the certificate store, I think the key has to be marked as "exportable" otherwise I don't think you can export the private key..

How to compare two X509Certificate2 c#

How can I compare two X509Certificate2 objects?
I need to find whether two certificates are same. It's for user authentication purpose and I need to find if both the certificates are of the same person.
Can I use its serial number or thumprint properties? or is there any other methods?
Also I am new to this and would like to know is it safe to use X509Certificate for user authentication?
A thumbprint is a unique value for the certificate, it is commonly used to find a particular certificate in a certificate store. More...
The serial number is a unique number issued by the certificate issuer. More...
As #Rattle pointed out:
The Equals method should not be used when comparing certificates for
security purposes. Instead, use a hash of the RawData property, or the
Thumbprint property.
Late to the party (recently needed to compare two X509 certificates myself).
The X509Certificate class has an Equals() method:
Two objects are considered equal if they are X509Certificate objects
and they have the same issuer and serial number.
using System;
using System.Security.Cryptography.X509Certificates;
public class X509
{
public static void Main()
{
// The paths to the certificate signed files
string Certificate = #"Signed1.exe";
string OtherCertificate = #"Signed2.exe";
// Starting with .NET Framework 4.6, the X509Certificate type implements the IDisposable interface...
using (X509Certificate certOne = X509Certificate.CreateFromCertFile(Certificate))
using (X509Certificate certTwo = X509Certificate.CreateFromCertFile(OtherCertificate))
{
bool result = certOne.Equals(certTwo);
Console.WriteLine(result);
}
}
}
Late, but...
Please note that an X509 certificate is, essentially, a binding between an identity (a distinguised name, the 'name' of the certificate owner) and a public key, signed with the private key of a third-party (known as Certification Authority or CA).
X509 certificates are public, and they can be cloned, copied, etc. A certificate alone is not enough for authenticating its owner.
Authentication schemes typically must ensure that the owner possess the private key associated with the public key in the certificate, typically by performing a private-key operation like signing a challenge (a nonce or random sequence of bits). The receiver then verifies that the operation was performed with the proper private key (using the public key in the certificate). Only when both keys come from the same pair that verification will succeed (this is the essence of public key cryptography).
And, additionally, the receiver must validate the certificate: look at the issuer and owner identities, check that the issuer is an approved CA, that the certificate is appropriate for the intended usage (Validity Dates, Policy and Key Usage), that the certificate signature is valid by using the public key in the CA certificate -which is either directly trusted, or signed by a higher-level CA which is trusted-, that the certificate is yet valid (certificates expire, nothing is eternal!), and that the certificate is not revoked by the CA that emitted it.
An important thing pointed by #Rattle is that for comparing certificates (for example, when comparing a code signer's certificate with a set of approved certificates), you should not use the X509Certificate.Equals() method.
Compare the thumbprints instead.

How do you generate an x509Certificate based solely on a public key in RSA format?

I have an RSA public key in an XML format. I need to take this key and create an x.509 Certificate using that public key. I do not have access to the private key to complete the key pair. All examples that I have found involve either generating the key pair or having access to both the public and private keys.
Below is a small snippet from a test routine I have been working on to accomplish this.
RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
provider.FromXmlString("<RSAKeyValue><Modulus>puEVvRbrLAz.......c1W5j/vqJSUrXo16k=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>");
Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters key = Org.BouncyCastle.Security.DotNetUtilities.GetRsaPublicKey(provider);
//<!*** Do some code to take RsaKeyParameters and create an x.509 Certificate ***>
var fOut = new System.IO.StreamWriter(#"C:\certificate.pem", false);
var pw = new Org.BouncyCastle.OpenSsl.PemWriter(fOut);
pw.WriteObject(key);
Just to clarify the issue of impossibility of generating a certificate using a public key only.
AFAIK, certificate must be signed. And it must be done with a private key - that's why you need one for generating a certificate. If certificate is signed with the paired private key of the open key you are going to issue a certificate for, than it is a self-signed certificate. Otherwise you need a private key of so called Certificate Authority for signing.

Categories