noxxi / p5-io-socket-ssl

IO::Socket::SSL Perl Module
36 stars 60 forks source link

Client cert chains should not be required to be built #24

Closed frioux closed 9 years ago

frioux commented 9 years ago

Server certificate files can (and arguably should!) be a single file with the chain of certificates concatenated all the way down to the root certificate. This is efficient and simple.

Unfortunately, client certificates do not work this way, and will only read the first certificate in a file and will only build the cert to the root cert, requiring the user to have all of the certificates that the client cert is based on (ie all the certs in the chain) in the CA store of the client.

For simplicity's sake I'd rather only store my root CA in my CA store, and have the client and server both just have chainfiles instead of single pem files. I suspect that the reason this works this way is that it's how OpenSSL works by default, as s_client from openssl acts the same way. But curl, which uses openssl on my system, allows the user to set client cert file which is a chainfile, so I suspect it's doable, just a bit of work.

I can try my hand at figuring this out, but I am mostly a pure-perl dev and don't know much about the guts of OpenSSL, XS, and other weird stuff like that. If I were to do this I'd see how curl is doing it.

noxxi commented 9 years ago

Client certificates work this way too. If you look with wireshark or at the traffic or use openssl s_server ... you will see, that it sends not only the leaf certificate but also the chain certificates, the same way as the server does send its certificate and chain. But there seem to be some strange things going on with doing the verification of the client certificate containing a chain, which I can see with openssl s_server too.

frioux commented 9 years ago

I think you misunderstand me; I'm not saying you shouldn't need a chain at all. The problem is that for client certs, the library must figure out the chain by looking at the client cert and the certificate store. I want to give it a signle file with all the certificates concatenated, like you can with a server.

noxxi commented 9 years ago

If you give IO::Socket::SSL a single file with SSL_cert_file and this file contains multiple certificates, then it will use the first one as the leaf certificate and the rest as chain certificates. That means all of these certificates will be transferred to the peer within the SSL handshake. This works not only for server side certificates but also for client side certificates.

If you still think I misunderstood you then I would suggest that you create some example code to show which behavior you see and which behavior you expect. Please make sure to make clear which version of IO::Socket::SSL, Net::SSLeay and OpenSSL you used with your example code.

frioux commented 9 years ago

Huh! Ok I did not find that to be the case, I'll be make a demo. Thanks

sent from a rotary phone, pardon my brevity On Jan 16, 2015 12:52 AM, "Steffen Ullrich" notifications@github.com wrote:

If you give IO::Socket::SSL a single file with SSL_ca_file and this file contains multiple certificates, then it will use the first one as the leaf certificate and the rest as chain certificates. That means all of these certificates will be transferred to the peer within the SSL handshake. This works not only for server side certificates but also for client side certificates.

If you still think I misunderstood you then I would suggest that you create some example code to show which behavior you see and which behavior you expect. Please make sure to make clear which version of IO::Socket::SSL, Net::SSLeay and OpenSSL you used with your example code.

— Reply to this email directly or view it on GitHub https://github.com/noxxi/p5-io-socket-ssl/issues/24#issuecomment-70215227 .

noxxi commented 9 years ago

But there seem to be some strange things going on with doing the verification of the client certificate containing a chain, which I can see with openssl s_server too.

These problems vanish and verification succeeds once the client certificate has the valid purpose to be used as a client certificate, that is NetscapeCertType must be client.

frioux commented 9 years ago

Ugh, I can't seem to get my example to work because I can't get my server to require a client cert! Shouldn't SSL_verify_mode => SSL_VERIFY_PEER be all that's required, on the server side, to force the client to send a cert?

noxxi commented 9 years ago

Yes, that's all what is needed and it works for me.

frioux commented 9 years ago

Yeah I believe it. Something else weird is going on over here. Don't worry too much about this; I suspect my environment is messed up since the way you say it should work is what I want anyway. I'll get something that shows... something at some point :)

noxxi commented 9 years ago

You might have a look at https://github.com/noxxi/p5-io-socket-ssl/tree/issue-24/stuff to get sample code and certificates.

frioux commented 9 years ago

Ok, this is a step in the right direction I guess. I took your example and made a couple small changes to it. Check out the client-validation branch from https://github.com/frioux/TLS-eg. If you run make it will generate all the certs for you. If you run miniserver.pl and then just do curl -k https://localhost:8443 you'll note that you do indeed get a response, despite the fact that peer validation is enabled. I have the latest IO::Socket::SSL installed; my OpenSSL is 1.0.1f. Can you reproduce this?

noxxi commented 9 years ago

With the option SSL_VERIFY_PEER which you used in your example the server only asks the client for a certifcate and it will fail if a client sent a certificate which could not be verified. But the client might still omit the certificate and the connection will succeed. Only with SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT it will also fail if the client did not send a certificate at all.

frioux commented 9 years ago

Ohhh, sorry that I missed that. Thanks for your help so far!

frioux commented 9 years ago

ok well, I now have code that works well and works the way I want. I suspect the whole time I was just missing the SSL_VERIFY_FAIL_IF_NO_PEER_CERT. Thanks again and sorry for the noise!