[gnutls-devel] session ticket key rotation

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[gnutls-devel] session ticket key rotation

Daniel Kahn Gillmor-7
Hi GnuTLS folks--

I'm trying to add session tickets to a GnuTLS-enabled daemon.

I'm using gnutls_session_ticket_enable_server(), but it looks like there
is no way to smoothly rotate session ticket keys.  That is, as soon as i
call gnutls_session_ticket_enable_server(), all previously-issued
session tickets become invalidated.

What i'd prefer is for my server to have a pool of N session tickets
keys, and for me to expire (and replace) one of them (in sequence) every
K seconds.

The tickets issued by this setup would have some reserved space that
indicated which of the slots is in use (e.g. the top 3 bits, if N = 8).

When encrypting, we'd always select the most recently-regeneratted slot,
and we'd set those bits to correspond to the slot in use.

When decrypting, we'd select the key to decrypt with based on the
corresponding bits.

With this scheme, tickets issued by each key would be good for at least
(N-1)*K seconds (in the case where a ticket is issued from the key just
before the next key is generated), and there would never be a hard
cutover that invalidates all existing session tickets.

Is there a way to do this in GnuTLS as it currently stands?  If not,
would you be interested in such a feature?

I'm imagining that an opaque server-side API for this would look
something like:

    struct gnutls_ticket_key_pool_int;
    typedef struct gnutls_ticket_key_pool_int *gnutls_ticket_key_pool_t;

    int gnutls_ticket_key_pool_init(gnutls_ticket_key_pool_t *pool, int numkeys);
    int gnutls_ticket_key_pool_free(gnutls_ticket_key_pool_t pool);
    int gnutls_ticket_key_pool_rotate(gnutls_ticket_key_pool_t pool);

    /* new value for gnutls_credentials_type_t */
    GNUTLS_CRD_SESTKT_KEYPOOL

Users would associate the ticket key pool with a session using
gnutls_credentials_get and gnutls_credentials_set, making the workflow
and memory ownership model aligned with existing use.

The caller would be responsible for invoking
gnutls_ticket_key_pool_rotate() at their selected intervals.

The opacity of the object might cause trouble if you wanted to share the
pool session ticket keys across a pool of front-end servers, or if you
wanted session tickets to survive a server reboot.  You could handle
that situation by adding a pair of serialization/deserialization
functions for the ticket key pool.

Any thoughts?  Is there already a good way to do something like this in
the existing API and i'm just missing it?

      --dkg


_______________________________________________
Gnutls-devel mailing list
[hidden email]
http://lists.gnupg.org/mailman/listinfo/gnutls-devel

signature.asc (979 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [gnutls-devel] session ticket key rotation

Nikos Mavrogiannopoulos
On Sun, Nov 13, 2016 at 9:25 PM, Daniel Kahn Gillmor
<[hidden email]> wrote:
> Hi GnuTLS folks--
> I'm trying to add session tickets to a GnuTLS-enabled daemon.
> I'm using gnutls_session_ticket_enable_server(), but it looks like there
> is no way to smoothly rotate session ticket keys.  That is, as soon as i
> call gnutls_session_ticket_enable_server(), all previously-issued
> session tickets become invalidated.

Hi Daniel,
 Right, it was intended for the applications to handle such rotation,
and a smooth rotation is not possible as I see with the current API.

> What i'd prefer is for my server to have a pool of N session tickets
> keys, and for me to expire (and replace) one of them (in sequence) every
> K seconds.
> The tickets issued by this setup would have some reserved space that
> indicated which of the slots is in use (e.g. the top 3 bits, if N = 8).
> When encrypting, we'd always select the most recently-regeneratted slot,
> and we'd set those bits to correspond to the slot in use.
>
> When decrypting, we'd select the key to decrypt with based on the
> corresponding bits.

Seems reasonable.

> Is there a way to do this in GnuTLS as it currently stands?  If not,
> would you be interested in such a feature?

Certainly. My goal for the new releases is to make it as simple as
possible for applications to use gnutls. I no longer try to push to
applications all the hard parts :)

> I'm imagining that an opaque server-side API for this would look
> something like:
>     struct gnutls_ticket_key_pool_int;
>     typedef struct gnutls_ticket_key_pool_int *gnutls_ticket_key_pool_t;
>
>     int gnutls_ticket_key_pool_init(gnutls_ticket_key_pool_t *pool, int numkeys);
>     int gnutls_ticket_key_pool_free(gnutls_ticket_key_pool_t pool);
>     int gnutls_ticket_key_pool_rotate(gnutls_ticket_key_pool_t pool);

The tricky part would be making the rotate function semantics easy to
use, even in multi-threaded environments, and allow efficient access
to keys at the same time. You wouldn't want a multi-threaded server to
hold a lock in order to access a ticket key.

That's not an easy goal to achieve; something similar using atomic
variables of C11 (with fallback) was done in gnutls_rnd() (see
random.c and  _gnutls_rnd_init).

> Users would associate the ticket key pool with a session using
> gnutls_credentials_get and gnutls_credentials_set, making the workflow
> and memory ownership model aligned with existing use.

The change in semantics by that would be that the credentials
structure would no longer hold only read-only data. However, if the
rotation is transparent for all types of applications, I have no
objection on that.

> The opacity of the object might cause trouble if you wanted to share the
> pool session ticket keys across a pool of front-end servers, or if you
> wanted session tickets to survive a server reboot.  You could handle
> that situation by adding a pair of serialization/deserialization
> functions for the ticket key pool.

Serialization and de/serialization would simplify things a lot for
applications. It would require some versioning though to allow
upgrading to a new ticket key handling at the future.

> Any thoughts?  Is there already a good way to do something like this in
> the existing API and i'm just missing it?

I do not think so.

regards,
Nikos

_______________________________________________
Gnutls-devel mailing list
[hidden email]
http://lists.gnupg.org/mailman/listinfo/gnutls-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [gnutls-devel] session ticket key rotation

Daniel Kahn Gillmor-7
Hi Nikos--

On Mon 2016-11-14 18:38:38 +0900, Nikos Mavrogiannopoulos wrote:
> and a smooth rotation is not possible as I see with the current API.

ok, at least i wasn't missing anythingn obvious :/

> Certainly. My goal for the new releases is to make it as simple as
> possible for applications to use gnutls. I no longer try to push to
> applications all the hard parts :)

This is the right choice, thanks :)

>> I'm imagining that an opaque server-side API for this would look
>> something like:
>>     struct gnutls_ticket_key_pool_int;
>>     typedef struct gnutls_ticket_key_pool_int *gnutls_ticket_key_pool_t;
>>
>>     int gnutls_ticket_key_pool_init(gnutls_ticket_key_pool_t *pool, int numkeys);
>>     int gnutls_ticket_key_pool_free(gnutls_ticket_key_pool_t pool);
>>     int gnutls_ticket_key_pool_rotate(gnutls_ticket_key_pool_t pool);
>
> The tricky part would be making the rotate function semantics easy to
> use, even in multi-threaded environments, and allow efficient access
> to keys at the same time. You wouldn't want a multi-threaded server to
> hold a lock in order to access a ticket key.
Is the problem the expense of taking a read lock itself, or is the
problem a risk of uninitialized memory access?

> That's not an easy goal to achieve; something similar using atomic
> variables of C11 (with fallback) was done in gnutls_rnd() (see
> random.c and  _gnutls_rnd_init).

 Is it possible that it doesn't matter?  Consider the following (very
 rough) implementation (error checking omitted for concision):

     1   typedef char[SESTKTKEYLEN] _session_ticket_key;
     2  
     3   struct gnutls_ticket_key_pool_int {
     4          int numkeys;
     5          _session_ticket_key *keys;
     6          int current_key;
     7   }
     8
     9   int gnutls_ticket_key_pool_init(gnutls_ticket_key_pool_t *pool, int numkeys) {
    10       *pool = malloc(sizeof(gnutls_ticket_key_pool_int));
    11       (*pool)->numkeys = numkeys;
    12       (*pool)->keys = malloc(sizeof(_session_ticket_key) * numkeys);
    13       (*pool)->current_key = 0;
    14       gnutls_rnd(GNUTLS_RND_KEY, (*pool)->keys, sizeof(_session_ticket_key) * numkeys);
    15      
    16   }
    17   int gnutls_ticket_key_pool_rotate(gnutls_ticket_key_pool_t pool) {
    18      _session_ticket_key newkey;
    19      gnutls_rnd(GNUTLS_RND_KEY, newkey, sizeof(newkey));
    20      int newkeyidx = (pool->current_key + 1)%pool->numkeys;
    21      memcpy(pool->keys[newkeyidx], newkey, sizeof(newkey));
    22      pool->current_key = newkeyidx;
    23   }


if someone offers a session ticket that belongs to the oldest keyslot
(the one that's about to be overwritten), and the crypto code that
accesses it to decrypt the ticket is in use during the memcpy on line
21, what's the worst that could happen?  It seems to me like the
decryption would fail, and the session wouldn't be able to resume.  This
is the *same* outcome as if it were to happen *after* the the function
completes (because that specific key has been overwritten by data that
can't dcrypt any subsequent message.  The outcome is, the client has to
go through a full handshake.  doesn't seem too bad...

> The change in semantics by that would be that the credentials
> structure would no longer hold only read-only data. However, if the
> rotation is transparent for all types of applications, I have no
> objection on that.

What different kind of application types should i be concerned about
that might behave differently?

> Serialization and de/serialization would simplify things a lot for
> applications. It would require some versioning though to allow
> upgrading to a new ticket key handling at the future.

a bytewise copy of the pool->keys member seems like it ought to do the
trick, and the reasoning about write-collisions looks to me like a
full-buffer memcpy is equivalent to the discussion about internal key
rotation, no?

wdyt?

        --dkg

_______________________________________________
Gnutls-devel mailing list
[hidden email]
http://lists.gnupg.org/mailman/listinfo/gnutls-devel

signature.asc (979 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [gnutls-devel] session ticket key rotation

Nikos Mavrogiannopoulos
On Mon, Nov 14, 2016 at 3:57 PM, Daniel Kahn Gillmor
<[hidden email]> wrote:

> Hi Nikos--
>> The tricky part would be making the rotate function semantics easy to
>> use, even in multi-threaded environments, and allow efficient access
>> to keys at the same time. You wouldn't want a multi-threaded server to
>> hold a lock in order to access a ticket key.
>
> Is the problem the expense of taking a read lock itself, or is the
> problem a risk of uninitialized memory access?
>
>> That's not an easy goal to achieve; something similar using atomic
>> variables of C11 (with fallback) was done in gnutls_rnd() (see
>> random.c and  _gnutls_rnd_init).
>
>  Is it possible that it doesn't matter?  Consider the following (very
>  rough) implementation (error checking omitted for concision):
>
>      1     typedef char[SESTKTKEYLEN] _session_ticket_key;
>      2
>      3     struct gnutls_ticket_key_pool_int {
>      4            int numkeys;
>      5            _session_ticket_key *keys;
>      6            int current_key;
>      7     }
>      8
>      9     int gnutls_ticket_key_pool_init(gnutls_ticket_key_pool_t *pool, int numkeys) {
>     10         *pool = malloc(sizeof(gnutls_ticket_key_pool_int));
>     11         (*pool)->numkeys = numkeys;
>     12         (*pool)->keys = malloc(sizeof(_session_ticket_key) * numkeys);
>     13         (*pool)->current_key = 0;
>     14         gnutls_rnd(GNUTLS_RND_KEY, (*pool)->keys, sizeof(_session_ticket_key) * numkeys);
>     15
>     16     }
>     17     int gnutls_ticket_key_pool_rotate(gnutls_ticket_key_pool_t pool) {
>     18        _session_ticket_key newkey;
>     19        gnutls_rnd(GNUTLS_RND_KEY, newkey, sizeof(newkey));
>     20        int newkeyidx = (pool->current_key + 1)%pool->numkeys;
>     21        memcpy(pool->keys[newkeyidx], newkey, sizeof(newkey));
>     22        pool->current_key = newkeyidx;
>     23     }

One question is whether we would like the key_pool_rotate to protect
from parallel calls of the same function, or from calls with small
time difference.

> if someone offers a session ticket that belongs to the oldest keyslot
> (the one that's about to be overwritten), and the crypto code that
> accesses it to decrypt the ticket is in use during the memcpy on line
> 21, what's the worst that could happen?

What about CPUs where writing to a memory location is not an atomic
operation... i.e., if on line 22, some reader instead of getting the
old or the new value of pool->current_key, gets some intermediate
value? Are these of a concern?

>> The change in semantics by that would be that the credentials
>> structure would no longer hold only read-only data. However, if the
>> rotation is transparent for all types of applications, I have no
>> objection on that.
> What different kind of application types should i be concerned about
> that might behave differently?

I cannot think of any.

regards,
Nikos

_______________________________________________
Gnutls-devel mailing list
[hidden email]
http://lists.gnupg.org/mailman/listinfo/gnutls-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [gnutls-devel] session ticket key rotation

Daniel Kahn Gillmor-7
On Tue 2016-11-15 01:47:03 +0900, Nikos Mavrogiannopoulos wrote:
> One question is whether we would like the key_pool_rotate to protect
> from parallel calls of the same function, or from calls with small
> time difference.

I think locking key_pool_rotate against itself doesn't sound like it
would be harmful, but i also don't see why it would matter.  in the
worst case, you just make it so that some sessions cannot be resumed,
which means that clients would fall back to slightly longer handshakes.

And if someone really wants to invalidate all existing session tickets
without destroying the ticket pool, i don't see why they shouldn't be
allowed to rapidly cycle the pool.

So i guess simpler seems better to me -- i don't see the need for locks.

> What about CPUs where writing to a memory location is not an atomic
> operation... i.e., if on line 22, some reader instead of getting the
> old or the new value of pool->current_key, gets some intermediate
> value? Are these of a concern?

So i can imagine, say, the first half of the RAM being from key N and
the second half of the RAM being from key N+1 for that slot.  In that
case, no existing tickets for that slot (which had been issued nearly a
full rotation cycle ago) would validate during that window.  but that's
fine, they're about to be invalidated anyway.  The bigger risk would be
if new tickets were issued during that case, but that wouldn't happen
because we update current_key *after* the key is updated.  So i still
don't see a problem.

Thanks for the thoughtful review!  let me know if you have any other
concerns or suggestions about the proposal.  If you think it's in decent
shape, should i open a gitlab ticket to track it?  I don't know if i can
get around to implementing it soon, alas, but i know it would be useful
for at least a couple implementations i'm concerned about.

Regards,

       --dkg

_______________________________________________
Gnutls-devel mailing list
[hidden email]
http://lists.gnupg.org/mailman/listinfo/gnutls-devel

signature.asc (979 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [gnutls-devel] session ticket key rotation

Nikos Mavrogiannopoulos
On Tue, Nov 15, 2016 at 7:14 AM, Daniel Kahn Gillmor
<[hidden email]> wrote:

>> What about CPUs where writing to a memory location is not an atomic
>> operation... i.e., if on line 22, some reader instead of getting the
>> old or the new value of pool->current_key, gets some intermediate
>> value? Are these of a concern?
> So i can imagine, say, the first half of the RAM being from key N and
> the second half of the RAM being from key N+1 for that slot.  In that
> case, no existing tickets for that slot (which had been issued nearly a
> full rotation cycle ago) would validate during that window.  but that's
> fine, they're about to be invalidated anyway.  The bigger risk would be
> if new tickets were issued during that case, but that wouldn't happen
> because we update current_key *after* the key is updated.  So i still
> don't see a problem.

The thing is that there is no guarrantee from the language about the
contents of the intermediate values. For practical purposes though, I
think variables which are word-aligned should be ok to access (though
the safe C11 version is something I prefer, even if it is within
ifdefs).

> Thanks for the thoughtful review!  let me know if you have any other
> concerns or suggestions about the proposal.  If you think it's in decent
> shape, should i open a gitlab ticket to track it?

Makes sense.

regards,
Nikos

_______________________________________________
Gnutls-devel mailing list
[hidden email]
http://lists.gnupg.org/mailman/listinfo/gnutls-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [gnutls-devel] session ticket key rotation

Nikos Mavrogiannopoulos
On Tue, Nov 15, 2016 at 8:26 AM, Nikos Mavrogiannopoulos
<[hidden email]> wrote:
>> Thanks for the thoughtful review!  let me know if you have any other
>> concerns or suggestions about the proposal.  If you think it's in decent
>> shape, should i open a gitlab ticket to track it?
> Makes sense.

Hi Daniel,
 I'm getting back of this because I find it quite interesting to have
even if there is no immediate plan to implement it. Could you add a
ticket describing your idea in the gitlab issue tracker?

regards,
Nikos

_______________________________________________
Gnutls-devel mailing list
[hidden email]
http://lists.gnupg.org/mailman/listinfo/gnutls-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [gnutls-devel] session ticket key rotation

Daniel Kahn Gillmor-7
On Fri 2017-03-03 09:35:17 -0500, Nikos Mavrogiannopoulos wrote:

> On Tue, Nov 15, 2016 at 8:26 AM, Nikos Mavrogiannopoulos
> <[hidden email]> wrote:
>>> Thanks for the thoughtful review!  let me know if you have any other
>>> concerns or suggestions about the proposal.  If you think it's in decent
>>> shape, should i open a gitlab ticket to track it?
>> Makes sense.
>
> Hi Daniel,
>  I'm getting back of this because I find it quite interesting to have
> even if there is no immediate plan to implement it. Could you add a
> ticket describing your idea in the gitlab issue tracker?

i've just opened https://gitlab.com/gnutls/gnutls/issues/184

sorry that i don't have any patches to offer yet!

thanks,

        --dkg

_______________________________________________
Gnutls-devel mailing list
[hidden email]
http://lists.gnupg.org/mailman/listinfo/gnutls-devel
Loading...