I am using the X509Store in C# DotNet to traverse the certificate stores. However, I am not clear on what the difference is between a certificate location and a certificate store. For example, the locations are LocalUser and LocalMachine. Examples of Stores are My (Personal) and Root. What is the difference between the Personal store on LocalMachine versus Personal store on LocalUser? What does it even mean to have a Personal store on LocalMachine?
There are a few purposed stores (C# name in bold, UI display name in parenthetical italics):
My (Personal): when searching for a leaf/end-entity certificate this store is usually what gets searched. This is usually the only store that has certificates with associated private keys.
If you browse to a site using client authentication certificates IE will choose candidate certs from the My store. (Forward reference: The location for this is CurrentUser)
When configuring IIS from a GUI it will show certificates from the My store. (Forward reference: The location for this is LocalMachine)
Root (Trusted Root Certificate Authorities): When doing a chained-trust decision, such as in TLS, if the other end of the chain is represented in this store then the original cert is trusted.
In addition to the certs explicitly in this store it exposes a virtual view over AuthRoot.
AuthRoot (Third-Party Root Certification Authorities): When registering an additional trusted root you "should" do it in the 3rd party store, for... reasons? While the LocalMachine one seems to work fine, the CurrentUser one seems to mostly be for show.
CertificateAuthority (Intermediate Certificate Authorities, known as "CA" to the underlying system): This is a repository of known intermediate certificates. When doing a chain build the system will look for a parent here, then in Root, then maybe over the Internet. If the chain was trustworthy then the certs in the middle of the chain may be cached here for future lookups.
Disallowed (Untrusted Certificates): If a part of a certificate chain is found in this store, the chain is considered untrustworthy.
AddressBook (Other People): A collection of certificate that you know about. Yep, about that specific. It gets searched by some programs/libraries when trying to match a peer certificate. For example, a find-by-issuer-and-serial-number notice in SignedXml.
There are a couple more standard ones, you can read about them at TechNet. You can also create your own certificate store using the X509Store(string, StoreLocation) overload. (It's sometimes useful for managing applications, but the certificate manager UI gets a bit confused when you have private keys in a custom store; it expects them only in the My store).
So that's StoreName. StoreLocation is perhaps better thought of as "store owner". A standard user could decide that they trust certificates issued by some private CA, so they could add it to their Root store. Since it's their store it won't affect any other users on the system. The system itself also owns stores. For example, the TLS certificate for the computer really belongs to "the computer", and multiple administrators may be involved with managing it. Since it's pretty unusual to search through your friend's stuff, the StoreLocation comes down to "me, as a user" (CurrentUser) or "this computer" (LocalMachine) for which store to use.
Things get slightly murky now: On Windows almost every CurrentUser store (with a notable exception of the My store) exposes a view into the LocalMachine equivalent store. So when you enumerate the certificates in CurrentUser\Root you're getting both the certificates explicitly added to CurrentUser\Root and also the certificates explicitly added to LocalMachine\Root. This can cause confusion since you can see a certificate when enumerating, call Remove with it as an argument, and it's still there when enumerating again.
In my experience, most interactions with cert stores are to the My store. At which point the decision tree comes down to something like this:
Am I a service with a dedicated user account?
new X509Store(StoreName.My, StoreLocation.CurrentUser)
Am I service without a dedicated user account?
new X509Store(StoreName.My, StoreLocation.LocalMachine)
Else
new X509Store(StoreName.My, StoreLocation.CurrentUser)
But that's a big generalization.
The personal store for LocalMachine contains machine certificates. An example of a certificate that lives in such store is a SSL certificate that is used by IIS to protect HTTP traffic. There is only one such store on the machine.
The personal store for LocalUser contains user certificates. An example of such certificate is an S/MIME certificate used to sign email messages. Each user has his/her own store of this type.
Related
Context
The client code have to connect to a remote web api. SSL is mandatory because of sensitive information exchanged on the wire. We have our self issued certificate a
In the project there is no currently what is properly configured in the remote IIS, and everything tested OK, except the certificate is not trusted.
I know I can install the certificate on the local machine and trust in it. However for some reasons (for example, there are Xamarin Android clients too) it is not a suitable solutions.
Current workaround is to simply ignore the certificate error in code, which is working both on desktop both on Android Xamarin:
ServicePointManager.ServerCertificateValidationCallback =
(s, certificate, chain, sslPolicyErrors) =>
{
// Here I would like to check against that the certificate
// is the specific one I issued, and only that case return with true
// if (what is the most suitable to write here?)
return true;
};
Question
Note: this is development/testing phase. In production there will be a certificate installed created by a trusted certificate authority.
Now I have bad feeling about accepting anything, so I would like to narrow it.
How to check against that the certificate is the specific one I issued, and only that case return with true.
Is that a working idea to run the code, place a breakpoint, and get the certificate.Thumbprint, then write an if to check against it?
(edit)
...or better... get the PublicKeyString and checking against it?
Checking against thumbprint is IMHO an OK option. With thumbprint you can narrow the trust to exactly one certificate.
Checking against public key or Subject Key Identifier is also OK but you will expand the trust to the same key pair. There can be several certificates issued on the same public key (with or without the same Distinguished Name).
As #bartonjs stated another option is to check raw data. This approach has the same power as checking against thumbprint. The benefit of this would IMO be that when you look at the code a year from now you will still know what certificate you trust :)
Anyway when checking against the exact certificate keep in mind that the certificate will expire someday (i.e. let's encrypt issues a 3 month certificate if I remember correctly) and your application will have to be redeployed with a new certificate check. You would have to keep track of expiration date of the certificate.
I am attempting to build an application that would make use of client-certificates to authenticate the user attempting to access the application. I am using a self-signed CA as described here. While, I have done quite a bit of research, I have yet to come away with the "proper" approach to authenticating a client-certificate.
First, it seems as if this can be done at both the application level (using .NET classes such as X509 store) or in IIS itself. What are the advantages or disadvantages of each approach?
If I were to choose to validate the certificate with in my application code, what is the proper field to validate? For example, this question uses the serial number. However, for my "test" certificates, the serial number is literally four characters (not counting spaces). What is the proper approach to ensuring that the client-certificate really was issued by me?
I attempted to apply this at the server level (I am using IIS Express for testing). However, I do not get a request for a certificate, just a 403.7 - Forbidden, error ( with the following web.config settings <access sslFlags="Ssl,SslNegotiateCert,SslRequireCert" />). However, if I remove SslRequireCert, I am able to at least "see" many certificates using the following code snippet:
X509Store store = new X509Store(StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
X509Certificate cert = store.Certificates[0];
Even if this issue (3) were resolved, is there any way, using IIS, to authenticate a certificate without having to map it to a Windows account?
I have tried installing the client certificate both in Firefox and in my PCs keystore. Thanks for any guidance.
I'm trying to develop an ASP.net site that reads the clientCertificate to ensure a smart card was used to access the website (trying to do away with username/password login).
The process I have in my mind is:
User registers an account and C# records user's clientCertificate (public).
The user can then log in the next time with that same clientCertificate, and they are now an authenticated user if hash valid.
I will use the code below to ensure authenticity of certificate. The browser should deal with private keys and ensure the certificate was NOT faked.
Based on Subject+certificate combination, C# assigns them their role-access.
The following code can be used for authenticity of certificate right?
X509Certificate x509Cert = new X509Certificate(Request.ClientCertificate.Certificate);
SHA1 sha = new SHA1CryptoServiceProvider();
byte[] hashvalue = sha.ComputeHash(Request.ClientCertificate.Certificate);
byte[] x509Hash = x509Cert.GetCertHash();
// compare x509Hash WITH hashvalue to ensure they are a match.
// If not, possibly faked certificate, not a real smartcard???
Is this how SmartCard authentication process should work???
If you just need to authenticate users with client certificates you should do this in IIS. You do not need to add any code at all to your application:
Specify Whether to Use Client Certificates (IIS 7)
Unless you need to link client certificates with database accounts or perform an additional validation step. But still for client certificate authentication I would stick with IIS settings.
Update:
In case you need to manipulate the client certificate you can do:
X509Certificate2 x509Cert2 = new X509Certificate2(Page.Request.ClientCertificate.Certificate);
And then access its properties such as:
x509Cert2.Subject
However, leave the validation piece up to IIS. If the client presents a bad certificate your asp.net code will not even execute since IIS will reject it
See this thread, sir. You do not need to verify authenticity explicitly in your code. IIS will do it for you.
Does IIS do the SSL certificate check or do I have to verify it?
IIS even tries to check revocation lists (however, this is often disabled if the CRL is large). An OCSP responder should be used to validate in cases where the CRL is very large or latency in checking it is high http://www.axway.com/products-solutions/email-identity-security/identity-security/va-suite.
Client-certificate authentication is done during the SSL/TLS handshake.
It is usually done using a Public Key Infrastructure, whereby the server has a (fixed) list of trusted CA certificates which it uses to verify the client certificate (in the same way as clients to it for the server). Once the certificate is presented to your application after this stage, you will know that:
the client has the private key for that certificate (guaranteed by the Certificate Verify message in the TLS handhsake (the SSL/TLS stack will verify this for you, no need to implement anything);
the client has the identity described in the certificate, because you will have verified it against your trusted CA.
The verification against a trusted CA requires the user to be registered with that CA in advance. You can't just authenticate any certificate if it hasn't been issued by a CA you trust. (Mapping the certificate's subject to a local user ID is another matter: you could do this upon first connection if needed: have your own database or directory service to map the Subject DN to another kind of user ID in your application, for example.)
User registers an account and C# records user's clientCertificate
(public). The user can then log in the next time with that same
clientCertificate, and they are now an authenticated user if hash
valid.
It sounds like you want to allow any certificate to be presented and use it for the initial registration, without necessarily resorting to a commonly trusted CA.
This is possible in principle, and I've done this to explore alternatives to PKI in Java.
To do this, you need to let any certificate through as far as the SSL/TLS handshake is concerned, and verify the certificate itself later. (You do need to use some form of verification.) You are still guaranteed with this that the client has the private key for the public key certificate it has presented.
Doing this requires two steps:
You need to be able to advertise the fact that you're going to accept any certificate, by sending an empty list of certification authorities in the Certificate Request TLS message (explicitly allowed by TLS 1.1).
Configure the SSL/TLS stack to trust any certificate (once again, when you do this, do not forget to implement your own verification system within your application, otherwise anything will really get through).
In .Net, while it should be possible to address the second point using a remote certificate validation callback, I have never found a way to alter the first point (this was also asked in this question).
In Java, the JSSE's X509TrustManager allows you to address both points.
I'd like to use XMLDSIG for verifying that a .config file has not been tampered with. I also want to be able to verify the signature chain so that I can trust the signature.
I've got three certificates in the chain:
Root CA -> Intermediate Signing CA -> Signing Key
I check that the file is signed with a key that is issued by the intermediate CA.
I'd like to do this without installing any certificates in the user's Windows certificate store. These are self-signed certificates, so not every user is going to want me installing them in their Root store. I don't have a problem with installing them in my root store.
I have the original .CER files -- they're included in the Signature block, and I can include them with the verification code. I can build a certificate chain from this by using X509ChainPolicy.ExtraStore.
If the certificates are not installed in the root store, and I verify the chain, then X509Chain.Build returns false, and the chain has a X509ChainStatusFlags.UntrustedRoot in it.
Can I add trusted certificates just for the duration of this operation?
Assuming you have physical copies of the public keys of ALL signing certs in the trust chain, then this is possible by using the OpenSSL command line tool.
http://www.madboa.com/geek/openssl/#verify-standard
It's a bit of a steep learning curve at first, but a very powerful utility.
If you don't have the signing certs, then you cannot verify anything. That would be the same as trying to verify a human signature without having seen the original. You have nothing to compare to, so how could you verify the authenticity?
Update
There's something here perhaps that could help you:
http://social.msdn.microsoft.com/Forums/eu/clr/thread/1966a6e8-b6f4-44d1-9102-ec3a26426789
I'm relatively new to Windows development, but have just finished a small project. I want to make my application "verified" like a lot of other applications are. For example, when you launch the application and UAC pops up, it won't have the "publisher unknown" message with the yellow bar and should have a "Verified by: " section on it.
I hope I explained that correctly. Does anyone know how to do this? I am hoping it's not like SSL certificates where you have to pay money...
Please feel free to let me know if my question was unclear or if I am not explaining it the right way. Thanks!
Unfortunatley, yes, you do need to pay money.
What you need is a code signing certificate. You can get them from the below certificate authorities:
Thawte
VeriSign
Or if you are looking for a cheap one, I would buy one from here, that is where I got mine:
Tucows
Once you get your cert, you can integrate it into the build process to sign your application and it will show your name as the publisher.
This is known as code signing. If you want to generate your own certificate just for you, you can follow the instructions in this answer.
As Eaton suggests, you'll have to pay if you want one for public use. I recently purchased one for our BuildMaster software from http://www.instantssl.com/code-signing/index.html for 2 years at about $340.
Response to comment:
If I generated my own certificate, how would it work for me but not for everyone else (publicly)?
Steps 1 and 2 in the linked answer create a self-signed Certificate Authority (CA) and then add it to your Windows Certificate Store. Step 3 then generates the code signing certificate and specifies the issuing CA (the -ic switch). Since the issuer is a CA that was created in step 1 and then set to manually be trusted by you in step 2, the code signing certificate generated in step 3 appears to be signed by a trusted party on your machine.
There is no way it can be trusted by the public because you both generated the code signing certificate and the authority used to verify that its creator is actually who he says he is. Imagine if you were evil and put fake info in the code signing certificate that says the signer is Microsoft.com instead of Aaron! All certificates would useless if there was no trusted authority to verify the actual identity of signer.
When you order the certificate from a trusted CA, they'll verify your identity in some way. They'll probably ask for a scanned copy of your driver's license if it's for signing as your name, or something only the business owner would have like the articles of incorporation (we used our D&B D-U-N-S number to verify Inedo).
Once they have verified your or your company's identity, they'll send you a certificate that is trusted by typical web browsers that you can use to sign your executables and the public can be assured that it's actually you signing them because the CA would be whichever company you bought the certificate from. If you look in the Options section of your favorite web browser you can see which CAs are deemed trusted.
Beside bought certificates as #Eaton explained and selfcreated selfsigned certificates as #John Rasch suggested
you can try free comunitee-based certificates from http://cacert.org that works simmilar to pgp/gpg-s trustsystem. For codesigning you need a trust resumee of at least 100 points.
German users can also use free http://web.de certificates that also permits codesigning.
The drawback of this approach (as well as self-created certs) is that "verified" is only activ, if the operating system of the executing client has installed the root certificate of the signing agency which in 99% is not the case.
However Firefox knows cacert.org so certs from cacert can be used for https, java and silverlight but not for standard msie without installing the root certificate.
You can also buy a code signing certificate from StartCom (www.startssl.com) for roughly $49.90 for two years - a lot cheaper than Thawte, Verisign and the rest.