I know it's rarely used, but is it possible to access the client certificate in Snap?
If not, is it possible using a different web stack?
I know it's rarely used, but is it possible to access the client certificate in Snap?
If not, is it possible using a different web stack?
This is not available to you in Snap's snap-server
package, which I'm assuming is how you're running your server.
Buuuuut it's not difficult to build, either by forking or as a separate module (you'll have to copy some code over, though, since some internal values you'll need aren't exported). bindHttps
, located in Snap.Internal.Http.Server.TLS, is what you want to target. This function is largely a wrapper around calls to OpenSSL.Session from the HsOpenSSL
library, which itself is a loose wrapper around the OpenSSL library.
Lucky for us OpenSSL has full support for client certificates. You simply have to set the verification mode to SSL_VERIFY_PEER
. There are other knobs you can fiddle with too. You also have to make sure you install a certificate chain to actually verify the client certificate against. Chain of trust and all that jazz. For reference, see how nginx does it.
Even better, this function is exposed in HsOpenSSL
as the function contextSetVerificationMode :: SSLContext -> VerificationMode -> IO ()
. You'll notice that ctx :: SSLContext
exists in the definition of Snap's bindHttps
. All you'll have to do is either copy or fork that module and introduce your calls.
It would look something like this (unverified code alert):
± % diff -u /tmp/{old,new}
--- /tmp/old 2016-04-11 11:02:42.000000000 -0400
+++ /tmp/new 2016-04-11 11:02:56.000000000 -0400
@@ -19,6 +19,7 @@
ctx <- SSL.context
SSL.contextSetPrivateKeyFile ctx key
+ SSL.contextSetVerificationMode ctx (SSL.VerifyPeer True True (Just (\_ _ -> return True)))
if chainCert
then SSL.contextSetCertificateChainFile ctx cert
else SSL.contextSetCertificateFile ctx cert
The first boolean tells OpenSSL to fail if no client certificate is present. The second boolean tells OpenSSL that the client certificate is only needed on the first request and no longer needed on renegotiations. The third value is a callback. I think the right thing to do is to just return True in the callback. It's what nginx does, anyway.
© 2022 - 2024 — McMap. All rights reserved.