CGI and client certificate, or do we need a CGI spec

November 29, 2020 11:58 AM, "Remco" <me at rwv.io> wrote:

> Hi,
> 
> I've been working on a gemini server and implemented CGI by skimming
> through the CGI/1.1 spec (RFC 3875) and looking through some gemini
> server implementations a couple of weeks ago, to figure out what
> environment variables to provide.
> 
> => https://git.sr.ht/~rwv/dezhemini/tree/bf5b0ec4/dezhmnsrv.rkt#L253
> 
> Currently I'm playing around with client certificates (having learned a
> lot more about libopenssl and racket ffi than I bargained for) and was
> wondering what environment variables I want to expose to bring that
> information into CGI scripts. So I visited the list of gemini server
> software again, browsed some code and found 4 servers supporting both
> CGI and client certificates.
> 
> Here's what the expose.
> 
> # Jetforce
> 
> => https://github.com/michael-lazar/jetforce/blob/d2d1f63f/jetforce/protocol.py#L180
> 
> * AUTH_TYPE : "CERTIFICATE".
> * REMOTE_USER : client certificate X509 subject common name
> * TLS_CLIENT_HASH : certificate fingerprint
> * TLS_CLIENT_NOT_BEFORE : certificate start date
> * TLS_CLIENT_NOT_AFTER : certificate end date
> * TLS_CLIENT_SERIAL_NUMBER : certificate X509 serial number
> * TLS_CLIENT_AUTHORISED : "true" if certificate is validated by server CA store
> 
> # GLV-1.12556
> 
> => https://github.com/spc476/GLV-1.12556/blob/13d52b63/Lua/GLV-1/gateway.lua#L156
> 
> * AUTH_TYPE : "Certificate"
> * REMOTE_USER : client certificate X509 subject common name
> * TLS_CLIENT_HASH : certificate fingerprint
> * TLS_CLIENT_ISSUER : certificate X509 issuer
> * TLS_CLIENT_ISSUER_* : certificate X509 issuer sub fields
> * TLS_CLIENT_NOT_AFTER : certificate end date
> * TLS_CLIENT_NOT_BEFORE : certificate start date
> * TLS_CLIENT_REMAIN : certificate days left
> * TLS_CLIENT_SUBJECT : certificate X509 subject
> * TLS_CLIENT_SUBJECT_* : certificate X509 subject sub fields
> 
> # Gemserv
> 
> => https://git.sr.ht/~int80h/gemserv/tree/ebc22964/src/cgi.rs#L42
> 
> * AUTH_TYPE : "Certificate"
> * REMOTE_USER : client certificate X509 subject common name
> * TLS_CLIENT_HASH : certificate fingerprint
> 
> # The Unsinkable Molly Brown
> 
> =>
> https://tildegit.org/solderpunk/molly-brown/src/commit/48f9a206c03c0470e1
c132b9667c6daa3583dada/dyna
> ic.go#L151
> 
> * TLS_CLIENT_HASH : certificate fingerprint
> * TLS_CLIENT_ISSUER : certificate X509 issuer
> * TLS_CLIENT_ISSUER_CN : certificate X509 issuer common name
> * TLS_CLIENT_SUBJECT : certificate X509 subject
> * TLS_CLIENT_SUBJECT_CN : certificate X509 subject common name
> 
> Looking at these it's obvious everybody is looking at everybody else to
> see how they implemented it and just pick whatever they like, so it
> seems I am on the right track. ;-) Personally I like this minimal
> approach of the latter two and will probably go with no more than:
> 
> * REMOTE_USER : client certificate X509 subject common name
> * TLS_CLIENT_HASH : certificate fingerprint
> 
> Because when writing a CGI scripts these are the only things I would
> really need: a way to communicate with the user about their certificate
> (REMOTE_USER) and a way to distinguish between offered certificates
> (TLS_CLIENT_HASH). I won't need AUTH_TYPE because if I do get a
> TLS_CLIENT_HASH I'll know I can authenticate the user.
> 
> But that brings me to the real question here. Does gemini need a CGI
> spec? Given status code 42 for CGI errors, it kinda committed to
> something CGI-ish without actually stating what that is. The only
> server making the effort to implement CGI/1.1 is GLV but, IMHO, that
> isn't the kind of simplicity I am here for and it's a bit of a hack to
> be honest.
> 
> GLV does manage to make CGI scripts more portable, whereas other servers
> don't really make the effort. For instance, some don't provide
> PATH_INFO but do provide PATH_TRANSLATED and others provide neither. I
> would like to share my CGI-scripts and have them run anywhere but to
> make sharing easier something like a spec would be nice. What do you
> think?
> 
> Anyway, back to libopenssl and racket ffi..
> 
> Cheers,
> Remco

Some thoughts:

1. My gemini CGI library for Python assumes AUTH_TYPE is available because 
it should be. I could technically edit it to test for the existence of 
TLS_CLIENT_HASH but why should I, when AUTH_TYPE is how you're supposed to check?
2. I kinda like the idea of having as much info as we can give about the 
cert, although I do think there's something to be said about minimalism 
and finding a balance.

That being said, my proposal:

 - `AUTH_TYPE`: Certificate
 - `REMOTE_USER`: certificate subject CN
 - `TLS_CLIENT_HASH`: Hash of the client cert (with `ALGO:HASHBYTESGOHERE` format)
 - `TLS_CLIENT_NOT_AFTER`: End date
 - `TLS_CLIENT_NOT_BEFORE`: Start date
 - `TLS_CLIENT_ISSUER`: Issuer
 - `TLS_CLIENT_SUBJECT`: Subject

The assumption is that TLS_CLIENT_ISSUER and TLS_CLIENT_SUBJECT are in 
forms where the info can easily be parsed out (so no need for the 
sub-field variables, apart from REMOTE_USER being the subject CN). 
TLS_CLIENT_REMAINING isn't needed, either, since any programming language 
worth its salt is going to have a way to get the days between today and 
TLS_CLIENT_NOT_AFTER.

Just my two cents,
Robert "khuxkm" Miles

---

Previous in thread (3 of 11): 🗣️ René Wagner (rwagner (a) rw-net.de)

Next in thread (5 of 11): 🗣️ Sean Conner (sean (a) conman.org)

View entire thread.