On Jul 5, 2017, at 22:30, Bob Beck wrote:
On Thu, May 18, 2017 at 7:31 AM, Kyle J. McKay <mack...@gmail.com>
wrote:
RFC 5280 section 4.1.2.5 states:
To indicate that a certificate has no well-defined expiration
date,
the notAfter SHOULD be assigned the GeneralizedTime value of
99991231235959Z.
True enough.
Unfortunately, if sizeof(time_t) == 4, 9999-12-31T23:59:59Z cannot be
represented as a time_t value causing valid certificates to be
rejected
just because the notAfter value is after 2038-01-19T03:14:07Z.
Correct
So, I'll ask - what is the platform you are using that needs this?
OpenBSD does not, nor do most modern unix systems - So what platform
are we doing this for?
I make a Git OS X installer for older (and current) Mac OS X
(mackyle.github.io/git-osx-installer). I will, in the near future, be
providing a LibreSSL installer too and it can be used to redirect the
Git OS X Installer Git from the native SecureTransport to using
LibreSSL instead (prior to OS X 10.8 only TLS 1.0 is available via
SecureTransport). The installer must support 32-bit PPC and 32-bit
Intel in order to be compatible with older machines. Those have a 32-
bit time_t. I also see that my Raspberry Pi (it's not a "3") running
Raspbian has a 32-bit time_t, so LibreSSL portable out-of-the-box
would not work properly on it either (even on an RPi 3 I don't think
64-bit Raspbbian builds are officially supported yet).
I'm not asking it to be nasty, but to put it in a slightly different
context "OMG, windows 98 does not support this, but if you add this
code I can support windows 98". You and I both know what your answer
would probably be for the person with Windows 98, which is "Here's a
nickel kid, get a modern operating system".
Yes, well, I could also just build OpenSSL and use that instead, but
I'd much rather use LibreSSL. Initially I thought I was just going to
have to use OpenSSL, but then I poked around and worked out the
patch. So I'm willing to maintain that patch separately for the
LibreSSL installer since it's really such a tiny change. I'm just not
comfortable shipping a 32-bit installer for LibreSSL that can't
connect to current web sites, so I need to include the patch if I use
LibreSSL rather than OpenSSL.
We ripped out support for a lot of moribund platforms for a reason.
What platform are you using with 32 bit time where this is an
issue? I'm not saying no, I'm saying "convince me this matters for
anything relevant please", and I am open to being convinced.
It's really a portable-only change. The way the patch is written the
compiler will omit the changes unless sizeof(time_t) == 4, but that
does still leave that test in there making the code a bit less elegant.
Do you have some other suggestion for how I can ship a version of
LibreSSL for older Mac OS X systems that works with those certificates?
Some folks are deliberately hanging on to their PPC Macs because they
have legacy hardware/software that they need to use. Or they just
can't afford to plunk down 1K+ for a new system, they'd rather use
that money to eat. Those systems cannot be upgraded past Mac OS X
10.5. Even some Intel Macs with older graphic cards can't be upgraded
past 10.7 (thank you very much Cupertino). Macs are not quite as
cheap to replace as wintel so the kid will need more than a nickel. ;)
And the $5 Pi isn't 64-bit either.
My arguments are:
1) The compiler should produce exactly the same code before and after
patch for 64-bit time_t systems
2) 32-bit systems are going to be around for many years still; 32-bit
ARM platforms are everywhere
3) 32-bit systems typically have 32-bit time_t values (I'm not aware
of anything in the standard preventing use of a 64-bit time_t on a 32-
bit system but that doesn't seem to be happening, at least not yet)
4) 32-bit time_t has potentially still got over 20 years of life left
in it
5) There are already pre-trusted root certificates with post
2038-01-19 expiration dates (I've seen 2041 for example), the number
of these will continue to increase
6) The alternatives to LibreSSL are (a) OpenSSL [0.9.8zh, that's a
joke, right? "zh"!] (b) BoringSSL [will get you caught up in goo*le
specific stuff sooner or later] (c) GnuTLS [but it's GPL 3 and used to
have horrible benchmarks in comparison to OpenSSL, but perhaps that's
been addressed]. I'm sure there are more but those are obvious
choices. If you need to stay away from GPL 3 (for whatever reason)
then the only reasonable choice left for 32-bit time_t systems will be
OpenSSL. I admit there hasn't been a 1.0.2zh [yet] but it's already
at 1.0.2l. Then there's the OpenSSL 1.1.0 API changes. If folks
adopt OpenSSL to get 32-bit time_t support they will likely be gone
for good unless LibreSSL picks up the same API changes allowing them
to migrate back after they no longer need 32-bit time_t support.
This is all, of course, a LibreSSL-portable argument and doesn't apply
to the non-portable version, but there really aren't two versions of
the core LibreSSL files, are there?
The LibreSSL installer I'm creating will have 3 patches and a kludge
in it:
1) added OIDs for EV certificates -- this change has already been
picked up and committed, so this is really actually a backport now
since there hasn't yet been a LibreSSL portable release with it
2) the patch below
3) a netcat patch to provide "-T tlscompat" (to go with the pre-
existing "-T tlsall" option)
4) a compile kludge to redirect all "poll(...)" function calls to a
"pollcompat(...)" wrapper function that emulates poll() properly on
Mac OS X
(1) will shortly become unnecessary, (4) I'll always be stuck with.
I'm not exactly sure what the current status of (3) is. (2) I must
have for the reasons above. So it's not that big a deal to always be
stuck with (2) in addition to the others. They're all tiny changes
except for (4) which just does something with compiler options and a
tiny static library that provides the wrapper implementation but
doesn't actually change any LibreSSL code at all.
Cheers,
Kyle
Fix this problem by disabling the restriction in the X509_cmp_time
function
and "wrap" far in the future notAfter values to 2038-01-19T03:14:07Z
in the
tls_get_peer_cert_times function.
With both of these changes certificates with "no well-defined
expiration
date" as specified by RFC 5280 are again accepted on platforms where
the
sizeof(time_t) == 4.
In general, there's no reason that a notAfter value should not be
wrapped
to 2038-01-19T03:14:07Z on a system with a 32-bit time_t. The
system itself
can never have a time after 2038-01-19T03:14:07Z because of the size
of the
time_t type and so wrapping a notAfter date that is after
2038-01-19T03:14:07Z
to 2038-01-19T03:14:07Z can never result in any additional
certificates being
accepted on such a system.
Signed-off-by: Kyle J. McKay <mack...@gmail.com>
---
For those using the libressl-2.5.4.tar.gz distribution, an equivalent
patch that updates the tarball files instead can be found here:
https://gist.github.com/7d4d59bbae9e4d18444b86aa79d6f350
Without this patch (or an equivalent), libressl-portable is not a
viable
alternative to OpenSSL on systems with a 32-bit time_t.
It rejects valid TLS connections to any site that contains a
notAfter date
after 2038-01-19T03:14:07Z in any certificate in the chain.
Besides the special case date mentioned above, there are many root
certificates
already in use today that have notAfter dates beyond 2038-01-19.
These patches have been tested with libressl-portable 2.5.4 on a
system with
a 32-bit time_t. With both of these patches the "nc -c" command
successfully
connects to sites with certificates that include notAfter dates
after 2038-01-19.
If either patch is omitted, "nc -c" fails to connect.
src/lib/libcrypto/x509/x509_vfy.c | 3 ++-
src/lib/libtls/tls_conninfo.c | 8 ++++++--
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/src/lib/libcrypto/x509/x509_vfy.c b/src/lib/libcrypto/
x509/x509_vfy.c
index d8c09a12..c59bd258 100644
--- a/src/lib/libcrypto/x509/x509_vfy.c
+++ b/src/lib/libcrypto/x509/x509_vfy.c
@@ -1882,7 +1882,8 @@ X509_cmp_time(const ASN1_TIME *ctm, time_t
*cmp_time)
* a time_t. A time_t must be sane if you care about times
after
* Jan 19 2038.
*/
- if ((time1 = timegm(&tm1)) == -1)
+ if (((time1 = timegm(&tm1)) == -1) &&
+ ((sizeof(time_t) != 4) || tm1.tm_year < 138))
goto out;
if (gmtime_r(&time2, &tm2) == NULL)
diff --git a/src/lib/libtls/tls_conninfo.c b/src/lib/libtls/
tls_conninfo.c
index 5cdd0f77..a59b4ba2 100644
--- a/src/lib/libtls/tls_conninfo.c
+++ b/src/lib/libtls/tls_conninfo.c
@@ -142,8 +142,12 @@ tls_get_peer_cert_times(struct tls *ctx, time_t
*notbefore,
goto err;
if ((*notbefore = timegm(&before_tm)) == -1)
goto err;
- if ((*notafter = timegm(&after_tm)) == -1)
- goto err;
+ if ((*notafter = timegm(&after_tm)) == -1) {
+ if (sizeof(time_t) == 4 && after_tm.tm_year >= 138)
+ *notafter = 2147483647;
+ else
+ goto err;
+ }
return (0);
---