How can I check if a certificate is self-signed? - c#

I'm using C#.NET and need to install a bunch of certificates into the Windows certificate store.
I need to check which of those certificates are root certificates (i.e. self-signed), so I can install them into the "Trusted root certificates" store.
I'm using the standard X509Certificate2 class. My current idea is to check whether the Issuer and Subject are the same.
I've noticed that X509Certificate2 has Issuer - IssuerName and Subject - SubjectName.
Is it better to compare Issuer to Subject, or IssuerName to SubjectName? Or doesn't it really matter?
Also, is this a reliable method or would I be better off using another approach?

See this post: java - Find if a certificate is self signed or CA signed
While it's not C#, the comment from the solution notes
If the subject and issuer are the same, it is self-signed
means you're correct about the way you're trying to validate it.
IssuerName and SubjectName return a DistinguishedName which contains RawData (a byte[] containing the raw information for the issuer/subject). You'd be best off comparing this field, though I believe comparing Subject and Issuer is just as valid.
So, you could write something like this:
public static bool IsSelfSigned(X509Certificate2 cert)
{
return cert.SubjectName.RawData.SequenceEqual(cert.IssuerName.RawData);
}

Related

Use certificate when issuer is not is X509Store trusted roots for client authentication using Microsoft .NET framework

While working on this question, I identified that the problem is slightly different than initially stated, so I am changing title and description
I'm trying to authenticate myself against WebService using my client certificate. I am using WebRequest for that purpose. I need to use self-signed certificate, without registering it in Windows X509 trusted root store.
The way I know if client certificate is presented or not is by examining request object on the server
I tried to use code from this question as a guidance. It doesn't work on .NET. Here is my code:
var certificate = new X509Certificate2(Properties.Resources.MyCert);
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(host);
req.ClientCertificates.Add(certificate);
WebResponse resp = req.GetResponse();
var stream = resp.GetResponseStream();
What I observe is that even though req.ClientCertificates does contain certificate with a valid private key, that certificate is never presented to server. I get no indication from WebClient that certificate is not used during handshake.
If I put certificate into "trusted root", the code will work (even when certificate is not in "personal").
My questions are:
Since certificate is usable when it's placed in "trusted root", I assume it is likely due to policy or something of that kind. Is it possible to coerce .NET to ignore policy settings and use supplied client certificate during TLS negotiation?
If abovementioned coercion is not possible, is there a call which will tell me ahead of time, that certificate I am about to use is not usable, and will be ignored? Alternatively, if such call is not available, could I make WebClient fail indicating a certificate error, instead of silently skipping over?
NOTE: I am aware that configuring certificates as described by Microsoft will work. This is NOT what I am looking for. I don't want to register potentially insecure certificate in trusted root, because this is potentially security hazard. I want to use cert on client without registering in store, or at least to get an exception indicating that certificate cannot be used. I realize that there can be multiple reasons why certificate cannot be used for a session, but there must be an exception, or at least some sort of indication on the client side that it cannot use specified cert. Instead, client simply doesn't present one.
When you instantiate your X509Certificate2, is the PrivateKey property set? If it is null, you are missing the private key, meaning the SSL/TLS client will be unable to authenticate you.
Make sure you are loading the certificate from a PFX file (or similar) instead of a CER. These contain the private key, too. They are usually password protected for that purpose. See How to retrieve certificates from a pfx file with c#? for more info.

Given two X509Certificate how to tell if one is signed by the other

I have two serialized certificates in the DB from which I can construct the X509Certificate. How to tell if one certificate is signed by the other. I don't want to check based on the IssuerName as it is not reliable(for my scenario).
IssuerName property and Authority Key Identifier extension are the way to find relationships between certificates. Once you match them, you can verify if the supposedly parent certificate is actually the CA certificate of the one being checked. I am not sure that such checks are possible with .NET Framework alone, and our SecureBlackbox does this easily, with one method.

Read certificate from pdf

I'm using ITextSharp in order to read certificate informations from digitally signed pdf document.
The ITextSharp.Text.Pdf.PdfPKCS7 class exposes three properties:
Certificates (as list)
SignCertificate (as single object)
SignCertificateChain (as list)
How can I combine these three properties in order to achieve all info about a single certificate?
I'd be able to show all certificate path (all nested certificates).
Certificates gives you the list in no particular order, including certificates that weren't used for the main signature.
SignCertificate gives you the certificate of the actual signer.
SignCertificateChain gives you the list where the first Certificate is the SignCertificate, the next is the certificate of the instance that issued the SignCertificate, the next is the certificate of the instance that issued the previous certificate, and so on. This can return less certificates than Certificates, because only the certificates used for the main signature will be returned.
So you don't need to 'combine' the properties to show the certificate path, you just need SignCertificateChain. Note that your question isn't entirely clear:
'all info about a single certificate'
kind of contradicts with
'show all certificate path (all nested certificates)'
If you want to visualize the chain that resulted into the signing certificate, you need to look at more than a single certificate (unless the certificate was self-signed in which case there's only one element in the chain).

Clearly recognize a certificate in Windows certificate store

I'm developing a library which generates XML data and signates the generated XML. I've installed a pkcs12 certificate (generated with OpenSSL from pem file) into the windows certificate store.
I'm loading the certificate from C# code with
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
X509Certificate2 cert = null;
foreach (var item in store.Certificates)
{
if (item.SubjectName.Name.Contains("CN=IDENTIFIER"))
{
cert = item;
break;
}
}
store.Close();
In my case the CN identifier is: my prename + surname. The cert comes from a third party. So I think I have no influence on the identifiers.
And here comes the question:
Is there any way to identify exactly this certificate from C#. In future it could be possible, that multiple certificates have the same X509 parameters (CN etc etc).
Thank you in advance.
Yes, it's possible that CN contains the same identifier (eg. when the certificate is issued for business entity).
Certificates are usually distinguished by one of following combinations:
1) Issuer name (not CN, but RDN, complete name record with multiple fields) + certificate serial number (it's unique within one CA)
2) Issuer name + certificate hash
If you don't know the issuer name before searching for the certificate, you can present the list of found certificates to the user and once he select one of certificates, store certificate hash for future reference.
On smaller systems (end-user's computer) the number of certificates in MY store is usually small and the chance of hash collision is minimal. On large systems the chance is higher and that's why Issuer name is used as well.
Expanding on Eugene's answer...
The Certificates property of X509Store is an X509CertificateCollection.
You'll probably be interested in its Find method and the X509FindType. It offers a number of ways to search for a certificate. Strictly speaking, both the subject DN and the subject alternative names should matter to identify the entity associated with a certificate. However, few tools do this from a presentation point of view (this could get quite cluttered in a table for example).
As GregS and Eugene pointed out, the certificate thumbprint (also known as fingerprint/hash in other tools) will identify a specific certificate uniquely, irrespectively of its issuer. It can be used with X509FindType.
Thumbprints are used in multiple places in the Windows/.Net/SSL world. In particular, it's the way to pick a given certificate to install on an HTTPS port.

Client certs without using the keystore

I'm trying to figure out if there is any way to have a .NET client use a client certificate without involving the Windows keystore in any way.
I have a code snippet like this:
test1.Service s = new test1.Service();
X509Certificate c = X509Certificate.CreateFromCertFile(#"C:\test.pem");
s.ClientCertificates.Add(c);
int result = s.TestMethod();
However, this only works if I also have the certificate referenced in "test.pem" installed in my certificate store. I assume this is because the key is necessary for the negotiation. If I don't have the cert/key in the store, the cert is not sent with the request.
What I want to do is be able to provide both the certificate and private key from a file or files and not involve the Windows certificate store in any way.
Is there any way to do this?
I'm going to post an answer to my own post, but will leave it open to see if others can solve it different.
Basically, I'm punting. If you have a PKCS12 file (with both key and cert in it) you can use the X509Certificate2 class to load that file and use it, and it won't interrogate the keystore.
I could not find a way to do this with flat PEM key and cert files (like what you'd need with Python, for example).

Categories

Resources