raff/tls-psk

Best way to modify this to access pskIdentity?

Opened this issue · 2 comments

Hi Raffaele,

In my application, I need the TLS connection handler on the server to be able to positively identify the client. Ideally, I think this means I would want to modify the tls-ext.ConnectionState structure to add a field for pskIdentity, and somehow populate this field. I think I can make this work, but it looks non-trivial, because it looks like I would have to mess with the tls.KeyAgreement interface in order to do so and that seems messy. Before I start down this path, I was wondering if you had any suggestions on a better way to do this?

raff commented

If you look here: https://github.com/raff/tls-psk/blob/master/psk.go#L90 I have this interesting comment:

// ciphertext is actually the pskIdentity here psk, err := pskConfig.GetKey(string(ciphertext))
And looking at the client code in https://github.com/raff/tls-psk/blob/master/psk.go#L111 it does seem to pass the pskIdentity as the ciphertext. If that is true, and since you are implementing pskConfig.GetKey can you do your validation there and return an error ?

If this is not what you want, you need to give me more context because I don't know what "pskIdentity" you are referring to.

Hi,

Yes, that's the identity I need. What I'm trying to do is make that identity visible to the server process that is handling the connection. (For example, if I were using client-certificate-based authentication, and I accepted the connection in my main loop and immediately called func handleConn(c *tls.Conn){} I could examine c.ConnectionState().PeerCertificates within handleConn to figure out which client I am connected to. But ConnectionState() contains no information about the peer identity of a PSK connection.

As currently structured, PSK connections don't have a simple path to put the pskIdentity into the ConnectionState struct, because the identity is only visible within tls.KeyExchange.ProcessClientKeyExchange(), and none of the in/out parameters in that interface lend themselves to returning the ID back to the calling function, (handshake_server.go/doFullHandshake(),) where I have access to the Conn object. My current plan is to modify that interface to pass in the *tls.Conn from doFullHandshake() to ProcessClientKeyExchange() so that I can attach the pskIdentity to a new field in the Conn object and then later copy it into a new field in the returned struct when c.ConnectionState() is eventually called.

But you have given me an idea -- since I do have access to the GetKey function, and all connections are accepted in a single listener.Accept() loop, I could write the identity into a channel within GetKey and then pull it out in the accept loop after calling tls.Conn.Handshake().

It's not an ideal solution, because it slows down the peak rate at which I can accept connections, (since it forces me to accept a TCP connection and process the handshake completely before spawning a handler goroutine, so that I can be sure to get the right client identity value for each connection) But it lets me get something working without requiring further changes to the TLS stack, so I think I will try that first and see if I come up with a better general solution.