Self-signed TLS certificates in Intranet - c#

I'm writing a system in C#, which consists of REST API server, written with HttpListener and WPF client app, with HttpClient and I want to use HTTPS.
As far as I know, on the server side all I have to do is run HttpListener with prefix with https and bind my certificate (creted for example with makecert) to proper port - now all communication is encrypted.
On the client side, I have to put the public part of certificate in Current User store, so that it can be trusted.
The server is not public, each client has his own instance accesible only after logging in to their VPN.
My questions:
1. Are self-signed certificates secure enough? Is generating new certificate for new client more secure(for example, from license data)?
2. How do I generate the "public part" and "private part" of certificate? How do I ship it?
It isn't a bank, so I don't want to overkill security, but I don't want to go "trust all certificates" way.

Security in general hinges on how well protected your private key is. The algorithm used can be the same as on a public signed certificate.
There is no inherit security gain or loss in using a self signed certificate.
The bigger problem is the distribution of your public key among the member systems. If you run a domain wide CA on your domain controller, it should be relatively easy.
If you do not, you might be able to do it via Group Policy.
In any case it requires admin intervention to get it to run on all your systems and again should the private key be compromised.
The problem arises should you have external clients not connected to your DC. Then LetsEncrypt is definitely the better choice.

I believe that you'll have to add the public key of the self signed certificate to the Trusted Root Certification Authorities store as well.
That is offcourse cumbersome since you'll have to do this on every client ...
Can't you use certificates issued by LetsEncrypt ?

Related

SSL Self-Signed Certificate

First of all I know that I have a lot of misconceptions about fundamentals of SSL.
But before, I want to give information about my goal; There is a Windows forms application written in C# and there is a asp.net WebApi that is integrated to this Windows app. Clients those are connecting to API are written in several programming languages. We need to add SSL somehow. this is not a public application and clients will build their client apps with the client certificate we will give them.
And here are lines of my knowledge about SSL those can be wrong or right;
-Self-Signed Certificates are more secure than bought ones. Becuase some known certificates can made unsecure by apps like Charles.
-For this scenario that i mentioned above as goal, there must be three certificates separately;
root cert,
a server side cert related to root cert,
a client side cert related to server cert.
-Every client can have same client side certificate.
-Visiual Studio Command Prompt is enough to create these certificates.
Also I need a source of documents to complete all these steps.
Self-Signed Certificates are more secure than bought ones.
nope ... self signed certs are just certs that a client can not verify on its own because there is no trusted third party saying: "this cert is ok"
you have to have your own way of securely delivering the cert to the client, possibly by having an admin manually installing them or bundling them with your app...
if you have no control over some of the clients, things tend to get ugly with self signed certs...
For this scenario, there must be three certificates separately;
root cert,
a server side cert related to root cert,
a client side cert related to server cert.
as far as i understood, you want x509 certs for SSL/TLS to authenticate the server and to avoid MITM attacks, not for client recognition by the server
in this kind of scenario you need only one certificate, or maybe two if you want to base your own PKI on this later ...
the case with one cert:
create a keypair and selfsign a x509 cert with that ... private key stays with your server, the public key will be included in the cert, which is shipped with your application and also handed out to other developers for their clients to authenticate the server...
this certificate will be required to be used in the client application to authenticate the server during SSL/TLS handshake
this is basically certificate pinning
darwback: depending on the size of the clientbase it will become challanging to replace this cert
case with 2 certs:
same as above, but the self signed cert is actually a root cert that can be used to sign other certs, in this use case in particular: the server cert...
the self signed root cert can then be used by the client to verify that the root cert was used to sign the server cert, which makes replacing the server cert easier ...
you might want to do the later and also setup a certificate revocation list in case you need to invalidate a cert ...
-Every client can have same client side certificate.
all the client needs is (as #john already pointed out) the self signed server cert (case 1) / self signed root cert (case 2)
-Visiual Studio Command Prompt is enough to create these certificates.
please notice that the documentation of makecert states "The Certificate Creation tool generates X.509 certificates for testing purposes only."
apparently this limitation was lifted ...
I think what you are after is called certificate pinning.
SSL certificates are used in the following way by default:
Certificate is issued by some authority. Client (browser, operating system such as Windows, Android etc) has a list of authorities it trusts. If certificate is valid (not expired, issued for domain we are connecting to etc) and is issued by trusted authority - all is fine
There are a ton of different authorities and client cannot trust them all. Instead, it trusts certain selected "root" authorities.
Those "root" authorities delegate ability to issue certificates to other, smaller, authorities, to which those root authorities themselves trust.
This might go on, so there is a chain of trust: certificate is issued by authority A, which is trusted by authority B, which is trusted by "root" authority, which in turn is trusted by client (your operating system).
That model has several weak points, one of them is list of "root" authorities your client trusts. Someone, like your corporate admin, or your government, or ISP provider, can install or force you to install custom certificate to your trusted "root" authorities list. Then it can perform man-in-the-middle attack by intercepting your SSL traffic and reencrypt it with this custom certificate that was installed to the trusted list.
That way client will think that all is still secure, while in reality your traffic is intercepted and responses are recorded and\or modified.
If you don't like this - you can use certificate pinning. Idea is simple - you just embed expected certificate for your api endpoint in your software.
By doing that you don't any more need to trust any authorities or verifying chain of trust above. All you need to verify is that certificate presented during SSL handshake is exactly the same as you embed into software.
For that reason - you don't really need certificate issued by some authority and you can use self-signed certificate.
So if you follow this path - issue self-signed certificate and embed it (without private key of course) to software (send to clients) and instruct them to verify your server certificate presented during SSL handshake is exactly this certificate.
Drawback is of course that if your certificate is compromised or expired - you need to update all software. It's not a big problem if said software is controlled by you, but it might be a problem if software is controlled by third party.

Why HttpWebRequest.ClientCertificates is a collection

I'm curious to know why HttpWebRequest.ClientCertificates is a collection?
As far as I know, only one client certificate can be used (Is this merely true?) in client authentication.
An example of an application uses multiple client certificates, please?
While you can use only one leaf certificate for authentication you might want or need to send additional intermediate certificates so that the peer can build the trust path to the locally trusted CA certificate. This is true for both server and client certificates.

Access SignalR application running on localhost from browser

I have an application that can be downloaded from my website and run on user PC. This application doesn't do anything special and just allows the web page to access the scanner. It uses SignalR for communication.
Basically, I run SignalR server under WinForms application and have javascript client that tries to access it through http://localhost:8084/signalR.
Everything works fine when I use HTTP version of the web application, but fails, when I use HTTPS for my web application: Most of the browsers don't allow unsecured connections from a secure page.
So, I've created a self-signed certificate that is installed on user system during installation and it works fine for Chrome, IE and Opera, but fails for Firefox and Edge.
So I was thinking, is there a better way to access SignalR applications that are running on localhost from webpage under https?
There isn't a better way. You are correct in your understanding that "[m]ost of the browsers don't allow unsecured connections from a secure page". I believe there isn't a browser that will allow this. Therefore if you want to call out from a secured website, you must use a secured connection as well.
I don't know the issue you're experiencing with Edge, as I can confirm that it does work. Firefox will NOT trust a certificate in the cert store, even if it is a trusted root or has a trusted root certificate. You have to manually add an exception for this certificate. Details, or at least information that will let you find the correct method to do this, can be found here.
There are some things you have to do in order to make sure your certificate and configuration is correct. First, you have to have a well formed certificate with a public and private key and a well formed certificate authority cert with only its public key. By "well formed" I mean it must contain all information required by browsers for full trust, such as a Subject Alternative Name entry.
You can use OpenSSL to generate the CA, then use that to sign a certificate you will use for the SSL port. Export the CA's public key and the SSL certificate's public and private keys. Exporting the CA's private key is a MAJOR no no. That would allow third parties to create new certs from it and install them on your client's machine. The CA gets installed in the machine's Trusted Root Certification Authorities store. The SSL cert can go into the Personal/Certificates store.
Once you have these, you have to configure the URL/Port you will use for access and SSL using the netsh command line tool. Add a URLACL to allow the application to access the url and port (netsh.exe http add urlacl), and then assign the certificate to the port (netsh.exe http add sslcert ).
Having done all this, you should be good to go. The only real problems you should have are Chrome being very demanding about the configuration of your certificates and Firefox refusing to trust your CA certificate even though it is in your trusted certificate store. Bastard.
And for Edge, I can definitely guarantee if you do all the above it will work. If it doesn't, you need to consult the js console to see what errors it is throwing.

I have several questions about the SslStream Class and about certificates

I have looked at about 10-15 different pages about the SSlStream class and about certificates and I haven't found one that completely explains everything to me. So I have a bunch of questions.
I am currently working on some SslStream code and I have a question about certificates. From my research it appears that the server requires a certificate if we are using TSL12. And it appears optional that the client needs a certificate.
1) Now if we design a system that the client needs a certificate do we use the same certificate for the client and the server? Or do they both use different ones?
2) Also looking at the Microsoft SslStream help page:
https://msdn.microsoft.com/en-us/library/system.net.security.sslstream(v=vs.110).aspx
How does the code know if those are the expected certificates?
3) In the Property page on a project under Signing you can Create a Test Certificate. When you click that button it asks for a Password. If a password is used how would that affect the SslStream code? The code on the Microsoft help page above doesn't deal with that at all?
4) Once I have a certificate for the server and the client can I just place them in a directory or do I need to put them in the store?
Thanks.
You can find most answers to your questions here
These are the different certificates. Client certificate used to check client identity. Server certificate used to encrypt key materials and to authenticate itself.
What means expected? You mean whether the client certificate is correct? You can write your own login to check client and certificate. By default expiration date is checked, where it's revoked or not etc. Read there to clarify.
It will create certificate and to use private key you will need to provide password to get it from storage
The base usage is to put it into the store. But you can also get it from .pfx file. You can read there about geting the key from file
1) Now if we design a system that the client needs a certificate do we use the same certificate for the client and the server? Or do they both use different ones?
The best practice is "one certificate per purpose". Think of a server authentication certificate as the "Warner Bros. Studios" sign hanging on the building as you pull up to the guard shack, and a client authentication certificate as an employee ID badge. They both inform the other party what's going on, but it feels a little out of place to then walk down the street to Universal and show your big Warner Bros. sign as identification.
2) Also looking at the Microsoft SslStream help page: https://msdn.microsoft.com/en-us/library/system.net.security.sslstream(v=vs.110).aspx How does the code know if those are the expected certificates?
The server authentication certificate you provide is correct, because you provided it.
If you give only one client auth cert, that's correct, because you provided it.
If you give multiple client auth certs then it will use an acceptable CAs list provided by the server TLS handshake to reduce the list, then it takes the first one that was acceptable.
3) In the Property page on a project under Signing you can Create a Test Certificate. When you click that button it asks for a Password. If a password is used how would that affect the SslStream code? The code on the Microsoft help page above doesn't deal with that at all?
Certificates don't have passwords, but PFX/PKCS#12 files do. You need that password to load the file into an X509Certificate2 instance (e.g. new X509Certificate2("servercert.pfx", "1Potato2Potato3Potato4")). Since SslStream won't do the loading for you, it doesn't talk about passwords.
4) Once I have a certificate for the server and the client can I just place them in a directory or do I need to put them in the store?
They should work fine when loaded from a PFX (you need the private key, so it can't be just a .cer). If the certificates can be one-time loaded into cert stores you can avoid the problem of loading or hard-coding PFX passwords... but that just depends on your deployment needs.

Manually trust SSL certificate in C#

I am developing an application in C# that will communicate with a server over HTTP and SSL. Is there some way that I can have the program trust the certificate supplied by the server? This certificate would be distributed together with the software, so that it can identify the server without involving an external CA.
Clarification: I want my client application to trust a single certificate that has been hard-coded in the client so that it will only ever trust my own server.
You can use BouncyCastle.
Load your CA certificate into BC usign DotNetUtilities class using the FromX509Certificate(X509Certificate) function
Load the public key from the server certificate into BC.
Call Verify on the server certificates public key
This way you check the signature of the certificate. Which is the safest way. And also gives you the possibility to update the server certificate without updating the client. (As long as the CA is valid off course)
Source of Verify here: http://www.bouncycastle.org/viewcvs/viewcvs.cgi/csharp/crypto/src/x509/X509Certificate.cs?view=markup Line:540
In my opinion, I don't think you can do this and trust that you have a secure channel. Someone correct me if I'm wrong, but the CA trust chain in SSL isn't to just to verify that the thumbprint is a particular value (or some other part of the certificate). It proves that the the client is communicating with the correct server (due to a shared CA key). This illustration is a good reference. Skipping step 3, will not allow the server to prove its identity to the client (throw certificate validation).
so that it will only ever trust my own server
SSL guarantees this by using a shared CA certificate (like verisign etc). Maybe I don't understand why you would choose not to just use SSL as it was intended.
EDIT:
As the_ajp points out in his answer, there are libraries (like bouncy castle) that will do a full verification on the certificate chain. These can be called manually.

Categories

Resources