Page MenuHome GnuPG

Clock skew screws up expiration and usage of keys
Open, WishlistPublic

Description

Easily reproducible with --faked-system-time. Just create a key, and then list
it with the same faked time. Result:

teythoon@europa ...gscm-20161104T101525-run-tests-YIEG2z % gpg2
--faked-system-time $(date --date "2016-07-01" +%s) -k
74CED98E257A084F9E92CB67517912BA66E730CA
gpg: WARNING: running with faked system time: 2016-06-30 22:00:00
gpg: please do a --check-trustdb
gpg: key 517912BA66E730CA was created 78 seconds in the future (time warp or
clock problem)
pub rsa2048 2016-06-30 [SCEA]

74CED98E257A084F9E92CB67517912BA66E730CA

uid [ unknown] test key (do not use) <testkey@example.org>

teythoon@europa ...gscm-20161104T101525-run-tests-YIEG2z % gpg2
--faked-system-time $(date --date "2016-07-02" +%s) -k
74CED98E257A084F9E92CB67517912BA66E730CA
gpg: WARNING: running with faked system time: 2016-07-01 22:00:00
gpg: please do a --check-trustdb
pub rsa2048 2016-06-30 [C] [expires: 2017-06-30]

74CED98E257A084F9E92CB67517912BA66E730CA

uid [ unknown] test key (do not use) <testkey@example.org>

Details

Version
master

Event Timeline

justus set Version to master.
justus added a subscriber: justus.

Can you test this also with 1.4 (iirc, Debian has a tool to fake the sytsem time
for a process)

Because it took me a while to understand what is actually going wrong, a summary
of the problem: if we get an error such as "key 517912BA66E730CA was created 78
seconds in the future", then the key's flags will be wrong (below: SCEA instead
of C) and the expiration date will not be printed.

Neal, that is exactly what happens, thanks for writing it out.

Werner, yes, it also affects gpg1:

% faketime "2016-07-01" g10/gpg --edit foo
gpg (GnuPG) 1.4.22-beta2; Copyright (C) 2015 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

gpg: NOTE: THIS IS A DEVELOPMENT VERSION!
gpg: It is only intended for test purposes and should NOT be
gpg: used in a production environment or with production keys!
gpg: key 0707DEE4 was created 29 seconds in the future (time warp or clock problem)

pub 2048R/0707DEE4 created: 2016-06-30 expires: never usage: SCEA

trust: unknown       validity: unknown

[ unknown] (1). foo bar <foo@example.org>
% faketime "2016-07-02" g10/gpg --edit foo
gpg (GnuPG) 1.4.22-beta2; Copyright (C) 2015 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

gpg: NOTE: THIS IS A DEVELOPMENT VERSION!
gpg: It is only intended for test purposes and should NOT be
gpg: used in a production environment or with production keys!

pub 2048R/0707DEE4 created: 2016-06-30 expires: 2016-09-28 usage: C

trust: unknown       validity: unknown

[ unknown] (1). foo bar <foo@example.org>

There are two related problem, which are only related to the key listing:

We do not indicate in the output whether a user id is valid. Instead we show
the validity info from the trustdb regardless of the time conflict. Ths could
be changed for example to show "[invalid]" instead of "[full]". This covers all
cases which render a user id invalid and not just a time conflict.

Due to the invalid user id the key is also not valid but we do not indicate this
either.

By using --ignore-time-conflict the problem goes away but that is not a
solution. We need to properly indicate when a user id or Key is not valid even
when not doing --check-sigs. One way to do this would be to use the same tags
we use with --checks-sigs with -k for the used self-signatures. That
information is readily available.

Prototype in

https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=shortlog;h=refs/heads/justus/issue2826-0

this prototype turns the use of uninitialized values into errors that are easy
to detect. Fail early.

Can you develop a fix based on the result of your prototype? I mean a short fix
without all the code changes from the prototype.

There is no easy fix. We see the key usage as SCEA because pk->pupkey_usage ==
0 means 'default capabilities', and pk->expiredate == 0 means 'does not expire'.

Fixing this means being able to mark these fields as not valid, either by
initializing to a special value, or by having a separate bit to store the validity.

The former approach means taking away one more value and making it magical. It
requires a special 'not valid' value for every field, and the code has to be
changed to recognize that special value.

Using a separate bit is more general, so I went for that. Setting and testing
that bit is best done with introducing accessors. Asserting the valid bit in
the getters notifies us where to explicitly test for the validity.

Knowing where the problems are does not help if we have no way to know whether
the value in question is valid or not. Therefore, I don't see how to "lift" a
fix from the prototype.

For example, the prototype produces this crash:

% gpg --faked-system-time $(date --date "2016-07-01" +%s) -k foo@example.org
gpg: WARNING: running with faked system time: 2016-06-30 22:00:00
gpg: please do a --check-trustdb
gpg: key F35FB3E372211AFC was created 1 day in the future (time warp or clock
problem)
gpg: key F35FB3E372211AFC was created 1 day in the future (time warp or clock
problem)
gpg: Ohhhh jeeee: Assertion "(pk)->flags.valid_expiredate" in print_key_line
failed (../../g10/keylist.c:1861)

This is in print_key_line, I don't see how to fix this without being able to
tell whether the expiration time is valid or not.

What are the reasons that expredate is not valid?
merge_keys_and_selfsig() not called for sure, Anything else?

merge_keys_and_selfsig is called, but because of the clock skew no self
signature is considered and hence the expiredate is not initialized.

Okay. So the actual cause is that we print data for a key (usage, expire, and
possible more) which we should not do. That data comes from self-signatures and
those can't be verified because we have a time warp. That should be the same as
with invalid self-signatures - what do we do in that case?

It fails the very same way:

$ gpg --list-signatures simple
pub   rsa2048 2017-06-27 [C] [expires: 2018-06-27]
      57DE806EC450DCE48C6F6438D60D9550EA614064
uid           [ultimate] Simple Key (do not use) <simple@example.org>
sig 3        D60D9550EA614064 2017-06-27  Simple Key (do not use) <simple@example.org>
$ export GNUPGHOME=$(mktemp -d)
$ cp simple.broken.selfsig.gpg $GNUPGHOME/pubring.gpg
$ gpg -k
gpg: /tmp/tmp.Og9h8Cb5cc/trustdb.gpg: trustdb created
/tmp/tmp.Og9h8Cb5cc/pubring.gpg
-------------------------------
pub   rsa2048 2017-06-27 [SCEA]
      57DE806EC450DCE48C6F6438D60D9550EA614064
uid           [ unknown] Simple Key (do not use) <simple@example.org>
justus edited projects, added gnupg (gpg22); removed gnupg.

I encountered this bug again in production while creating keys on an air-gapped system that had the wrong time zone configured. I consider this kind of problem grave and embarrassing, but we failed to agree on a way to fix it in the foreseeable future.

werner lowered the priority of this task from Normal to Wishlist.Aug 8 2017, 11:14 AM
werner edited projects, added gnupg; removed gnupg (gpg22).

Also note that --faked-system-time is a debugging aid and nothing you should use under production. A wrong system time is a security problem anyway because it invalidates assumptions gpg takes. A small clock skew is annoying but the way to avoid is is easy enough.

Note that make has the same problem with clock skews. (ask NFS users on how grief that often caused ;-)

I decrease this to a wishlist and remove the 2.2 tag, because that is definitely nothing which will go into 2.2

This is not about faked-system-time, nor about misconfigured systems, it is about gpg using uninitialized or invalid data. This is one instance of that problem, and there could be more. I'm sorry if I failed to communicate this.