TLS certificates have at least two internal representations of time
utcc.utoronto.ca
utcc.utoronto.ca
Everything you Never Wanted to Know about PKI but were Forced to Find Out, by Peter Gutmann: https://www.cs.auckland.ac.nz/~pgut001/pubs/pkitutorial.pdf
Also, this, by the same person: X.509 Style Guide (which talks about the two date formats):
“In coming up with the worlds least efficient machine-readable time encoding format, the ISO nevertheless decided to forgo the encoding of centuries, a problem which has been kludged around by redefining the time as UTCTime if the date is 2049 or ealier, and GeneralizedTime if the date is 2050 or later (the original plan was to cut over in 2015, but it was felt that moving it back to 2050 would ensure that the designers were either retired or dead by the time the issue became a serious problem, leaving someone else to take the blame).
To decode a date, if it's UTCTime and the year is less than or equal to 49 it's 20xx, if it's UTCTime and the year is equal to or greater than 50 it's 19xx, and if it's GeneralizedTime it's encoded properly (but shouldn't really be used for dates before 2050 because you could run into interoperability problems with existing software). Yuck.
To make this even more fun, another spec at one time gave the cutover date as 2050/2051 rather than 2049/2050, and allowed GeneralizedTime to be used before 2050 if you felt you could get away with it. It's likely that a lot of conforming systems will briefly become nonconforming systems in about half a centuries time, […]”
Also, remember the OSI model? It was not supposed to be just a model — and it's a failure of the model anyway, real network protocols just keep piling up application layers on top of each other, the upper ones using the lower ones as their transport layers, — no, there were supposed to be actual separate protocols for each level, and actually there are! Of course, nobody sane ever uses them.
Reminds me of the old saying: a zebra is a horse designed by committee.
"In the past, Firefox was lenient, NSS still is lenient, but mozilla::pkix is strict. I found a comment in the mozilla::pkix which says the alternative encodings from asn.1 explicitly aren't allowed." - https://bugzilla.mozilla.org/show_bug.cgi?id=1152515 (2015)
An interesting comment in there also mentions how QA testing just one function with different dates might require changing the system date, but that would test more than just the one function... I wonder how many pieces of software might miss bugs due to complex tests like this.
This is why Let's Encrypt expects to still work for people on old Android phones that haven't seen a software update in many years, even after the root via which those phones trust Let's Encrypt "expires" later in 2021. Android doesn't check the expiry date on roots and these phones aren't getting updates so they won't be updated to stop trusting the obsolete root.
Time is one of the most difficult things to get right in software engineering.
[1] https://github.com/kstenerud/compact-time/blob/master/compac...
[2] https://github.com/kstenerud/concise-encoding/blob/master/ct... and https://github.com/kstenerud/concise-encoding/blob/master/ce...
We should start calling them the "927 club".
The xkcd pretty neatly summarized the situation as of now. You developed and self-promote a new standard but do not explain why anyone should care.
Linked in context with other response points and it's a worthy reference, but dropped without much further discussion and the onus feels like it remains on you to justify it.
I call him out for just re-inventing the wheel by mentioning the xkcd. He proposes a new standard in his repo. He doesn‘t explain why it‘s better (not in the repo, nor in the comment), just mentions that all others are bad.
I call him out for just re-inventing the wheel by mentioning the xkcd. And indeed, critical self-reflection is necessary when developing a standard - why is it necessary? What does it do better? Otherwise, it‘s just as in the xkcd - a standard that nobody will ever use.
And instead of explaining just that he choses to attack me.
But you‘re right, a little accompanying text wouldn‘t have hurt.
They don't appear to be attempting to cover all use cases (in particular, it isn't trying to be human-readable), and crucially they don't appear to be proposing it as a standard.
Yes sometimes its overused, but that doesn't mean its never right.
Since internet protocols are almost always talking in terms of events when it comes to time (and almost always in the past), RFC3339 is fine for its purpose. But for other uses of time it's not enough.
I did up a little summary of use cases here: https://github.com/kstenerud/compact-time/blob/master/compac...
It's completely unambiguous in every context, and reads and sorts better for humans then any other format.
I'll never understand why someone decided 02:00+01:00 should equal 01:00Z not 03:00Z.
Solving for UTC would then give UTC = CET-01:00. So if you want something equivalent to UTC without explicitly denoting the timezone it'd make more sense to denote 03:00 CET as 03:00-01:00 rather than 03:00+01:00.
I mean sure technically you're appending the timezone, but if you omit all the detail that makes it clear that it is a timezone then I just think it looks silly.
So, you have 02:00 in some local time, and you want to go to UTC? The change-of-basis transformation is "add 1 hour", because 01:00 (in UTC) plus 1 hour results in 02:00 (in local time), all perfectly reasonable, from an algebraist's point of view.
I wonder how long until we collectively decide to banish things like ASN.1 to the past like we are doing with C strings and parsing of untrusted network input in memory unsafe languages.
ASN.1: unsafe at any speed.
See also: https://en.m.wikipedia.org/wiki/X.690
Everything I read about x509-related serialization reminds me of that rant[1] about the PSD file format.
[1]: https://github.com/gco/xee/blob/master/XeePhotoshopLoader.m#...
Are these modern languages? I'm not aware of any modern ones that have a taint mode. Just Rust that has memory checking, Perl that has a simple taint mode, Ruby that has a more robust taint mode, and Jeeves which is like a general taint mode in a DSL in Python.
Valid criticism of ASN.1 would probably be that the abstract object model is too general on one hand and contains useless historical data types on the other (and the article is particular example of that). But that mostly is not related in any way to complexity and safety of the parsing or the currently popular meme of "unsafe" == bad.
As part of a project where I needed to parse X.509 certificates I wrote a simple ASN.1 -> X.509 parser which does the mapping in place. This can be found at [0].
So while it's possible to decode the structure of an ASN.1 object and many nested things, getting at a meaning requires understanding the schema of the objects being parsed since tags only describe the data type in a limited way.
For example, to get the public key from an X.509 certificate you can easily do that -- but it will be an opaque ASN.1 structure unless you know if it's an RSA key or an ECDSA key, which is encoded as data in another ASN.1 OID somewhere, not as PART of the ASN.1 tag.
So if you wanted to get the exponent for an X.509 certificate (like x509_to_exponent() does), then you need to know the schema for that type of public key -- here, it's specified in PKCS#1 (because only RSA is supported by this software), a completely unrelated standard.
[0] https://cackey.rkeene.org/fossil/artifact/bc9c145e70285c54?l...
But how come people have aversions with ASN1? Is it just stylistic as with XML? (And that it's used as the substrate for a bunch of old harebrained standards and protocols - all with artisanal shitghetti C codecs instead of the aforementioned robust parser + schema?)
ASN.1, on the other hand, has many more types (as we can see in this article!) including dates, big integers, choices, sequences, and more.
So yes, it makes things less "introspectable", but any serious protocol needs a well-defined schema anyway. (And that's why GraphQL and OpenApi/JsonSchema, and before that WSDL/SOAP were so popular.) It seems strange that people "hate" ASN1. At best the problem seems to be the libraries, or that no sane restricted subset has emerged over the years...?
For an X.509v3 public key, the ASN.1 would look like this in JSON-with-types:
[
[
[type:<oid>]: "1.2.840.113549.1.1.1",
[type:<null>]
],
[type:<bitstring>]: <encoded>[
[type:<bigint>]: 39054839120582390568029762340674230...,
[type:<bigint>]: 65537
]
]
"<encoded>" here means an ASN.1 value is serialized and then contained as a binary string.As you can see here, you only know the structure and type. This falls apart here at the "bitstring" value -- it's an opaque binary blob, which happens to be ASN.1 again, which you would only know if you know the schema.
If we converted this to something more self-describing it would look more like (borrowed kind of from TJSON):
{
"publicKeyInfo:<o<oid,...>>": {
"publicKeyType:<oid>": "1.2.840.113549.1.1.1",
"publicKeyParams:<null>": null
},
"publicKey:<o>": {
"n:<bigint>": "39054839120582390568029762340674230...",
"e:<bigint>": "65537"
}
}
Having this kind of human description in addition to the type and structure makes it easier to work with if you don't know what's inside the structures.Indeed, in the security community there is a trend to get rid of ASN.1. E.g. TLS uses a custom ad-hoc format:
https://datatracker.ietf.org/doc/html/rfc5246#section-4
And this is used by e.g. certificate transparency:
https://datatracker.ietf.org/doc/html/rfc6962#section-1.2
Maybe it's just a question of tooling, but personally I haven't found a binary format that is as nicely debugable as ASN.1. In many other instances I have to stare at hexdumps while for ASN.1, the lapo.it viewer exists. E.g. I still haven't been able to parse the extra_data of a certificate transparency log entry. In the case of ASN.1, you can dump it to lapo.it. How can you debug data in the ad hoc TLS format? There is literally no information in the binary format, you must know the schema.
That being said, it's indeed more difficult to write parsers for ASN.1 formatted data without using ASN.1 libraries. The ad hoc TLS format definitely has an advantage here. But IMO ASN.1 has way too much of a bad name.
I would use
conn = ssl.create_default_context().wrap_socket(socket.socket(socket.AF_INET), server_hostname=hostname)
conn.connect((hostname, 443))
cert = conn.getpeercert()
print(cert['notAfter'])
to test it.