Username/password authentication strategy

Hey Kevin,

Yes this solution sounds good, pin is passed as part of query string.
Username is still visible outside tls session of course.

But I think the bigger problem is that now I need to store usernames, pins,
all of user?s cert fingerprints and their first seen and last seen dates, I
would need to build an interface to delete old/lost fingerprints, etc.
Compare that to basic auth in http, which while might not be pretty,
involves very little code to implement: check username/password hash
against ones in db on every request (in a before filter if framework
supports it) and I?m done.

By the way, your solution is very similar to how client ssh usually works,
one would login using username/password into a new server or from a new
client, and then add their client certificate to ~/.authorized_keys. So far
yours is the best solution, but I wonder if there?s a simpler, more elegant
way.

On Mon, Jul 20, 2020 at 16:50 Kevin Sangeelee <kevin at susa.net> wrote:

> I see this as the same issue that exists for clients - without a trusted
> CA, there's nothing to stop me masquerading as anyone else, other than the
> certificate (e.g. fingerprint) pinning, so I believe the process absolutely
> needs a (one-time) login prompt to pin the certificate - I can't see a way
> to avoid it.
>
> Your question made me think about what would be the minimum steps required
> to implement client TOFU with PIN or password verification, and the code
> below is my take on what I think has to happen. Note the code is only meant
> as a concise way to discuss the process.
>
> So, for example, a request to a private resource, such as: -
>
> gemini://susa.net/cgi-bin/private.sh?articleId=1234
>
> Might be handled something like this: -
>
> $ cat private.sh
> #!/bin/bash
>
> # If we have no client certificate, request one.
> if [[ "${TLS_CLIENT_HASH}" == "" ]]; then
>
>     echo -ne "60 CLIENT CERTIFICATE REQUIRED\r\n"
>
> elif [[ $(grep "${TLS_CLIENT_HASH}" /tmp/${REMOTE_USER}_sigs) == "" ]];
> then
>
>     # We've never seen this user's client hash, so challenge for a PIN
>     # (we could store this current URL for onward forwarding)
>     echo -ne "30 /cgi-bin/login.sh\r\n"
>
> else
>
>     echo -ne "20 text/gemini\r\n"
>     echo "This is the prize inside the protected resource!"
> fi
>
> I think a redirect to a login process is unavoidable, because any
> originating request might have its own query_string, yet we're going to
> need one for the password prompt response. So the login.sh would be our
> one-time verification to pin the certificate to a CN based user-id.
>
> $ cat login
> #!/bin/bash
>
> # If we have no client certificate, request one.
> if [[ "${TLS_CLIENT_HASH}" == "" ]]; then
>     echo -ne "60 CLIENT CERTIFICATE REQUIRED\r\n"
>     exit
> fi
>
> # If the certificate has no CN, then reject it
> if [[ "${REMOTE_USER}" == "" ]]; then
>     echo -ne "20 text/gemini\r\n"
>     echo "Your CN can't be used as a user-id!"
>     exit
> fi
>
> # We have a client certificate, is it already authorised?
> if [[ $(grep "${TLS_CLIENT_HASH}" /tmp/${REMOTE_USER}_sigs) != "" ]]; then
>     echo -ne "20 text/gemini\r\n"
>     echo "You are already authorised!"
>     exit
> fi
>
> # We have a certificate and a valid user-id (CN), so either prompt for
> # a PIN, or verify PIN if we've been given a QUERY_STRING.
>
> # Grep the remote user's line from the passwd file (format CN:PIN)
> PWD_ENTRY=$(grep "^${REMOTE_USER}:" login_passwd)
>
> # Strip the CN value and separator, leaving the PIN
> MY_PIN="${PWD_ENTRY#${REMOTE_USER}:}"
>
> # Check for our PIN in the query string (which may be empty)
> if [[ "${QUERY_STRING}" == "${MY_PIN}" ]]; then
>     echo -ne "20 text/gemini\r\n"
>     echo "Your PIN checks out, ${REMOTE_USER}!"
>     echo "${TLS_CLIENT_HASH}" >>/tmp/${REMOTE_USER}_sigs
>     echo "Your hash has been stored in '/tmp/${REMOTE_USER}_sigs'"
>     exit
> fi
>
> echo -ne "11 Please enter your PIN, ${REMOTE_USER}\r\n"
>
>
> On Sun, 19 Jul 2020 at 20:26, Peter Vernigorov <pitr.vern at gmail.com>
> wrote:
>
>> I am trying to implement a simple authentication for my Gemini site,
>> and was planning to use a client certificate CN field to pass
>> username:password pair to server. However, upon reading closely about
>> the TLS handshake -
>> https://en.wikipedia.org/wiki/Transport_Layer_Security#TLS_handshake -
>> it seems that the client (just like the server) certificate is sent
>> before the ChangeCipherSpec record, i.e. insecure. That means to me
>> that the CN field would be passed before the TLS session is started
>> and therefore not suitable as an authentication medium. Is that
>> correct?
>>
>> Another alternative to implement username/password type authentication
>> in Gemini would be the sensitive input status code, but then I would
>> have to store a list of certificate fingerprint and username pairs,
>> greatly complicating the system.
>>
>> Given that Gemini protocol strives to be minimal/low-cost for both
>> users and client/server devs, has anyone found a simple way to
>> implement username/password type authentication systems? To be fair, I
>> have attempted to use client short-/long-lived client certificates as
>> per recommendation in Gemini protocol specification; however, if
>> access to the same "account" from multiple devices and being able to
>> survive certificate loss without permanently losing access is my
>> account are requirements, this authentication method quickly becomes a
>> mess. For example, think about how one would go about getting access
>> to their astrobotany plant on a new device. This is why I ended up
>> going back to username/password authentication, but having
>> difficulties making sure that everything is secure. In need of
>> help/suggestions/ideas, thanks.
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.orbitalfox.eu/archives/gemini/attachments/20200720/5bda
12bc/attachment-0001.htm>

---

Previous in thread (4 of 12): 🗣️ Kevin Sangeelee (kevin (a) susa.net)

Next in thread (6 of 12): 🗣️ Kevin Sangeelee (kevin (a) susa.net)

View entire thread.