Closed Bug 1601841 Opened 4 years ago Closed 3 years ago

about:certificate uses build locale's date format (instead of OS-configured date format) for validity dates, leading to day vs. month confusion

Categories

(Firefox :: Security, defect, P2)

71 Branch
defect

Tracking

()

RESOLVED FIXED
86 Branch
Tracking Status
firefox86 --- fixed

People

(Reporter: ianf, Assigned: Gijs, NeedInfo)

References

(Blocks 1 open bug)

Details

Attachments

(2 files)

User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0

Steps to reproduce:

  1. Go to nsa.gov in 71.0
  2. Display the certificate
  3. Note the validity dates are 11/9/2019, 8:49:31 AM (Australian Eastern Daylight Time) to 2/7/2020, 8:49:31 AM (Australian Eastern Daylight Time) - yours obviously in a different timezone
  4. Note that this is a Let's Encrypt certificate which should have a validity date of 60 days with no exceptions ever
  5. Go view the same site in another browser, and note the certificate validity is 60 days
  6. Save the leaf certificate
  7. Open the PEM files in whatever certificate viewer you want to use (I used XCA)
  8. Note the validity dates are (a) as expected for a Let's Encrypt certificate, (b) match other browser's reports, and (c) are different from the about:certificate display

Actual results:

Incorrect validity dates displayed for the certificate. Note: I have not checked whether this is a display issue, or whether validation would also have flagged this cert as correct past it's expiry. On that basis I am flagging it as a security issue until that's triaged.

Expected results:

Correct validity dates should be displayed.

Apologies - I forgot to attach the relevant leaf certificate.

(In reply to Ian Farquhar from comment #0)

User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0

Steps to reproduce:

  1. Go to nsa.gov in 71.0
  2. Display the certificate
  3. Note the validity dates are 11/9/2019, 8:49:31 AM (Australian Eastern Daylight Time) to 2/7/2020, 8:49:31 AM (Australian Eastern Daylight Time) - yours obviously in a different timezone

If this is 9th of November to 7th of February, this would be correct, right? Because when I follow these steps I see:

08/11/2019, 21:49:31 (Greenwich Mean Time)
06/02/2020, 21:49:31 (Greenwich Mean Time)

which looks correct to me (and looks like it matches your dates)? Chrome also shows me the same dates.

Is the issue just that date formatting on about:certificate in your locale is wrong, ie you're expecting dd/mm/yyyy but you're getting mm/dd/yyyy like the Americans?

Flags: needinfo?(ianf)
Component: Untriaged → Security

(In reply to Ian Farquhar from comment #0)

  1. Note that this is a Let's Encrypt certificate which should have a validity date of 60 days with no exceptions ever

To avoid confusion, it seems this value should be 90 days, not 60, per https://letsencrypt.org/2015/11/09/why-90-days.html .

The cert parsing code for about:certificate is completely separate from the validation code (the former being based on the PKI.js library while the latter is in our own C/C++ code), thus I think it's safe to open this up. In any case, I don't really understand the issue either, it sounds like a dupe of bug 1582356 but I'm not sure.

Group: firefox-core-security

(In reply to Johann Hofmann [:johannh] from comment #4)

The cert parsing code for about:certificate is completely separate from the validation code (the former being based on the PKI.js library while the latter is in our own C/C++ code), thus I think it's safe to open this up. In any case, I don't really understand the issue either, it sounds like a dupe of bug 1582356 but I'm not sure.

This seems plausible. For about:certificate, we at least have easy access to a privileged content so we might as well send the dates down localized based on the OS long-style date format (long-style rather than the current short style to avoid confusion like that which seems to have happened here).

(In reply to :Gijs (he/him) from comment #5)

(In reply to Johann Hofmann [:johannh] from comment #4)

The cert parsing code for about:certificate is completely separate from the validation code (the former being based on the PKI.js library while the latter is in our own C/C++ code), thus I think it's safe to open this up. In any case, I don't really understand the issue either, it sounds like a dupe of bug 1582356 but I'm not sure.

This seems plausible. For about:certificate, we at least have easy access to a privileged content so we might as well send the dates down localized based on the OS long-style date format (long-style rather than the current short style to avoid confusion like that which seems to have happened here).

Oh, right, that other bug is about about:certerror, this is about about:certificate. So not exactly a dupe, but maybe the same problem? Would be good to get confirmation from the report :)

Yeah, it shouldn't be hard to solve, just some things are more important :)

(Correct on 90 days not 60 days, and yes, it's about:certificate.)

A colleague (and Gijs too) just noticed that his is actually just a display issue. It's still a bug, but it's cosmetic.

Look at the dates from about:certificate:

11/9/2019, 8:49:31 AM (Australian Eastern Daylight Time)
2/7/2020, 8:49:31 AM (Australian Eastern Daylight Time)

My locale is set to EN-AU, meaning the date format is DD/MM/YYY, and the date is being correctly converted to AEDT, which is the current correct timezone. So using the locale I read this as 11th September 2019 to 2nd July 2020.

Look at the cert:

Saturday, 9 November 2019 8:49:31 AM
Friday, 7 February 2020 8:49:31 AM

That's GMT, which is currently 11 hours behind AEDT.

But if you realise that the about:certificate viewer is displaying are actually the US format MM/DD/YYYY - completely ignoring the locale settings - they're actually the same date. And because it is actually picking up the timezone, it's very easy to mis-identify.

This is a cosmetic display issue, not a security issue. But it needs to be fixed as validity dates should be clear, and so the date display should be regionally correct.

Flags: needinfo?(ianf)

(In reply to Ian Farquhar from comment #7)

But if you realise that the about:certificate viewer is displaying are actually the US format MM/DD/YYYY - completely ignoring the locale settings - they're actually the same date.

Yeah, the problem is the about:certificate page which is displaying these pages is effectively implemented as a webpage. It doesn't have access to your OS date formatting preferences, only the ones for Firefox's default locale. Your timezone is independent from your locale (this would be true even if we did use the OS formatting settings - people travel!).

Because you're using an en-US copy of Firefox the date isn't formatted as you might expect. As a short-term workaround, en-GB is also available and would have the right date formatting preferences, and based on a casual reading of wikipedia may be closer to Australian English in terms of spelling - so might be a better alternative until this bug is fixed...

(In reply to Johann Hofmann [:johannh] from comment #6)

Yeah, it shouldn't be hard to solve, just some things are more important :)

I want to push back slightly here: yes, it's "just" a formatting issue, and yes it's not exactly primary UI, and yes there's no actual security impact. But our en-US builds are often used by people who aren't in the US (I'm pretty sure we have data on this), and the fact that all our unprivileged pages get America's, uh, idiosyncratic, date format, much to the confusion of our users, is pretty unfortunate. I imagine it's going to also affect e.g. about:neterror / about:certerror, which is going to be pretty unhelpful.

Zibi, is there anything we can do to fix that in the short term? Like, we expose fluent on content-privileged about: pages now, can we do the same with mozintl, for instance?

Status: UNCONFIRMED → NEW
Ever confirmed: true
Flags: needinfo?(gandalf)
Summary: about:certificate Showing Incorrect Validity Dates → about:certificate uses build locale's date format (instead of OS-configured date format) for validity dates, leading to day vs. month confusion

Zibi, is there anything we can do to fix that in the short term? Like, we expose fluent on content-privileged about: pages now, can we do the same with mozintl, for instance?

Yeah, we have this - https://searchfox.org/mozilla-central/source/dom/webidl/IntlUtils.webidl & https://searchfox.org/mozilla-central/source/dom/webidl/Window.webidl#779

We could probably unify mozIntl around a single WebIDL (IntlUtils) and expose it to the same contexts as document.l10n is assuming the same privacy/fingerprinting rules apply.

Alternatively, we could also just set the default locale depending on the same rules - https://searchfox.org/mozilla-central/source/js/xpconnect/src/XPCLocale.cpp#127-140

this would make the default Intl.*Format(undefined, ...) select the right locale for all contexts that should use the browser locales and not the web exposed locales.

Flags: needinfo?(gandalf)

A question: why not short-circuit the entire date display confusion by presenting the date as a textual string. For example: 7/11/2019 becomes "11th September 2019" which is unambiguous irrespective of locale within a language set. The language in which this is expressed can reasonably be assumed from the browser's default.

As a short-term solution, I think that works.

Just FYI, yes I am using the US version of Firefox, because that's what's offered by default to Australian IP addresses. Current language variants are English (US), English (UK) and English (Canadian). Even if given the choice, Australians will usually opt for the US version over the UK one, simply because we use a US keyboard, not a UK one.

For example: 7/11/2019 becomes "11th September 2019" which is unambiguous irrespective of locale within a language set.

That doesn't resolve the problem. If the user is reporting en-US to websites, and uses tr locally, should we display the date 8 Aralık 2019 or December 8, 2019?

We're looking for a solution that covers that.

(In reply to Zibi Braniecki [:zbraniecki][:gandalf] from comment #11)

For example: 7/11/2019 becomes "11th September 2019" which is unambiguous irrespective of locale within a language set.

That doesn't resolve the problem. If the user is reporting en-US to websites, and uses tr locally, should we display the date 8 Aralık 2019 or December 8, 2019?

We're looking for a solution that covers that.

I'm confused. We're using app locale right now, right? And it's confusing when the date format of the app locale (en-US, ie mm/dd/yyyy) is different from the OS locale (en-AU in the reporter's case). Using en-US long form would be clear, and would be in the same language as the rest of Firefox and thus the rest of about:certificate ? Or are you saying that Intl's date formatting is based on Accept-Language locale instead of app language?

Flags: needinfo?(gandalf)

We're using app locale right now, right?

Not in web-content pages. In privileged pages, yes. Everything that goes through MozIntl retrieves regional prefs locales [0]. That is fairly fingerprinting prone because we look into OS for those locale bits as well [1]

For that reason for non-privileged pages, when they use regular Intl.* they only get app locales [2].

A lot of things improved since this has been designed (it predates me). I'd argue that now we should switch that to "web exposed locales" [3] for XPCLocale and just use the anti-fingerprinting for protecting users.

That would mean that unless you turn on one of the anti-fingerprinting protections, your JS Context locale will match your regional prefs (so privileged and non-privileged dates will be the same).

[0] https://searchfox.org/mozilla-central/source/toolkit/components/mozintl/mozIntl.jsm#28-33
[1] https://firefox-source-docs.mozilla.org/intl/locale.html#regional-preferences
[2] https://searchfox.org/mozilla-central/source/js/xpconnect/src/XPCLocale.cpp#117-141
[3] https://firefox-source-docs.mozilla.org/intl/locale.html#web-exposed-locales

Flags: needinfo?(gandalf)

I think Gijs is right that it shows too much now, and we have better tools to solve it. Let's try in this cycle.

Assignee: nobody → gandalf
Status: NEW → ASSIGNED

Mossop - I'm in https://searchfox.org/mozilla-central/source/js/xpconnect/src/XPCLocale.cpp and need to if/else for whether I'm in the web exposed JS Context, or not.

If I am, I'll fetch GetWebExposedLocales which will get regional prefs locales unless there's an override like StaticPrefs::privacy_spoof_english or intl.locale.privacy.web_exposed.
If I am in a "chrome" UI and not web exposed, I want to read regional prefs locales directly so that those overrides don't affect chrome UI.

What's the right API call to test?

Flags: needinfo?(dtownsend)

I'm even more confused than before now -

(In reply to Zibi Braniecki [:zbraniecki][:gandalf] from comment #13)

We're using app locale right now, right?

Not in web-content pages.

This says no.

<snip>
For that reason for non-privileged pages, when they use regular Intl.* they only get app locales [2].

This says yes.

Which is it?

FWIW, if we're increasing fingerprint-ability, even if only when privacy.resistFingerprinting is not on, you should probably check in with :tjr .

(In reply to Zibi Braniecki [:zbraniecki][:gandalf] from comment #15)

Mossop - I'm in https://searchfox.org/mozilla-central/source/js/xpconnect/src/XPCLocale.cpp and need to if/else for whether I'm in the web exposed JS Context, or not.

If I am, I'll fetch GetWebExposedLocales which will get regional prefs locales unless there's an override like StaticPrefs::privacy_spoof_english or intl.locale.privacy.web_exposed.
If I am in a "chrome" UI and not web exposed, I want to read regional prefs locales directly so that those overrides don't affect chrome UI.

What's the right API call to test?

I'm not Mossop so I'll leave the needinfo, but per https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_reference/JSRuntime, I don't think you can do so based purely on a JSRuntime - you need a JSContext, which has a principal that you can use for these checks. A single jsruntime can have contexts with several principals, AFAICT.

ISTM that exposing MozIntl to about: pages the same way we do with fluent would also allow solving this bug, without increasing our fingerprinting risks. Is there a particular reason not to go that route? (Are there difficulties with doing that that I'm not seeing?)

Flags: needinfo?(gandalf)

ISTM that exposing MozIntl to about: pages the same way we do with fluent would also allow solving this bug, without increasing our fingerprinting risks. Is there a particular reason not to go that route? (Are there difficulties with doing that that I'm not seeing?)

Yes, but the problem we face is a bit broader. We generally serve the sub-optimal locale to the JS Context, which means we have to continuously watch out for any PR that accidentally uses Intl.*Format(undefined, ...) in the context of chrome, because it has to use MozIntl.*Format(undefined, ...) only because in chrome privileged context the default locale is suboptimal.

I'd like to try to fix that.

I'm even more confused than before now -

Ahh, right, Sorry for that.

JSContext has a default locale, which is taken from Services.locale.appLocale. That is basically the negotiated app locale, which is usually "build locale" (say, Firefox-de has de) but can be also a locale negotiated in result of a langpack (Firefox-de with fr locale selected will use fr there).

MozIntl uses regional prefs locale which is a bit more sophisticated and can do things like looking into OS locale and selecting regional settings from it (so, if you have Firefox fr either from build or langpack, and your OS has fr-CA we can recognize that you want Canadian formats in your French build).

We so far tried to avoid exposing that -CA bit to the Web, but I'm not sure if it really matters that much, it just helps us work better in scenarios where we don't have a perfect regional Firefox release/langpack.

So, the web sees the locale of the product, while MozIntl allows for potentially more fine tuned locale choice, but falls back on the same.

The simple way out would be to just make JSRuntime get the regional prefs locale because we don't really save that much fingerprinting by sometimes hiding the region (for example, we have en-CA Firefox release, so for that release/langpack, we'll expose the region).

The challenge is that our API for that allows for a bunch of privacy oriented anti-fingerprinting overrides, and when the user turns them on they want to mask the locale send to the Web, but not switch their UI date/time formats.

So I need to say sth like "If it's exposed to the web, follow the web-exposed-locales, if it is not, just take regional-prefs-locales`.

If that's not possible, maybe we should move JS default locale to be per-context, not per-runtime?
Anba - what do you think?

Flags: needinfo?(gandalf) → needinfo?(andrebargull)

(In reply to Zibi Braniecki [:zbraniecki][:gandalf] from comment #17)

The challenge is that our API for that allows for a bunch of privacy oriented anti-fingerprinting overrides, and when the user turns them on they want to mask the locale send to the Web, but not switch their UI date/time formats.

We should already have a similar issue when RFP sets the process time zone to "UTC" instead of differentiating between chrome- and web-content. But to be fair when that code was added, it wasn't even possible to somehow support different time zones (in the JS engine).

So I need to say sth like "If it's exposed to the web, follow the web-exposed-locales, if it is not, just take regional-prefs-locales`.

If that's not possible, maybe we should move JS default locale to be per-context, not per-runtime?

Can the locale be tied to js::IsSystemCompartment resp. js::IsSystemRealm, or JSPrincipals::isSystemOrAddonPrincipal? So we only need store two locales per JSRuntime instead of a different locale per each JS::Realm. (I think JS::Realm is the correct place to store the locale instead of JS::Compartment or JSContext.)

Flags: needinfo?(andrebargull)

Can the locale be tied to js::IsSystemCompartment resp. js::IsSystemRealm, or JSPrincipals::isSystemOrAddonPrincipal? So we only need store two locales per JSRuntime instead of a different locale per each JS::Realm. (I think JS::Realm is the correct place to store the locale instead of JS::Compartment or JSContext.)

I never worked with JS Realms, so I'm not sure how to handle this transition.

I see that the JSRuntime::GetDefaultLocale is used in:

I'm not sure how to make it per-realm. Can you help me with that?

Flags: needinfo?(andrebargull)

(In reply to Zibi Braniecki [:zbraniecki][:gandalf] from comment #19)

I never worked with JS Realms, so I'm not sure how to handle this transition.

JS::Realm corresponds to a single global object (there's a one to one relationship between JS::Realm and js::GlobalObject). JS::Realm also corresponds to the Realm record in the ECMAScript spec.

I'm not sure how to make it per-realm. Can you help me with that?

Are the other mentioned alternatives (js::IsSystemCompartment resp. js::IsSystemRealm, or JSPrincipals::isSystemOrAddonPrincipal) not possible? If the alternatives can't be used, the next best thing to try is probably to use JS::RealmOptions. JS::RealmOptions consist of JS::RealmCreationOptions (not modifiable after the realm was constructed; preferred for non-dynamic options) and JS::RealmBehaviors (dynamic options). A new boolean option could be added to JS::RealmCreationOptions to select if the current Realm should use the Services.locale.appLocale or the regional prefs locale. The actual locale identifiers can still be stored in JSRuntime with this approach, we just need another set of JS_[Get,Set,Reset]DefaultLocale functions (or add a modifier argument to the existing functions) to set the regional prefs locale in the JSRuntime. The JS::RealmCreationOptions itself are passed to JS_NewGlobalObject when a new global is created. So for the globals which should use regional prefs locale instead of Services.locale.appLocale, the JS::RealmCreationOptions must then be adjusted to set this new flag.

Flags: needinfo?(andrebargull)

Are the other mentioned alternatives (js::IsSystemCompartment resp. js::IsSystemRealm, or JSPrincipals::isSystemOrAddonPrincipal) not possible?

Jeff - what's your position? I don't have any experience working with that area, so I don't think I can make any reasonable claims about what is and is not possible or should be done.

Flags: needinfo?(jwalden)

I'm unassigning myself temporarily. I'm still interested in resolving it, but it seems like we have three pieces here:

  1. We can fix this single case by using some IPC call to retrieve chrome-privileged mozIntl formatted date (not me)
  2. We can write DocumentL10n like WebIDL interface for MozIntl to enable us to use mozIntl in more contexts like this (not me, at least not anytime soon)
  3. We can fix how we select default Locale in SpiderMonkey so that when we're in UI JS Context we use different locale than web-exposed JS Context. (I thought it may be me, but it seems much deeper than I thought, so likely not me)

I'd argue that (3) is inevitable for us, because as we expose more of the mozIntl as part of the ECMA402, the sole reason for mozIntl existence that will remain is to tackle (3). So targeting (3) would likely supersede (2) and (1) and lead to less papercuts for Fx UI engineers. But I don't know how hard it would be so I can't evaluate whether it's feasible to try to address it now, or should we do (1) and/or (2) in the meantime.

Status: ASSIGNED → UNCONFIRMED
Ever confirmed: false
Status: UNCONFIRMED → NEW
Ever confirmed: true

I think Gijs covered what I would have said.

Flags: needinfo?(dtownsend)
Blocks: cert-viewer

Another option is to simply use ISO-8601 dates, although they're a lot less readable without timezones.

Flags: needinfo?(jhofmann)
Assignee: gandalf → nobody

I believe the Intl.*Format locale defaults are all wrong anyway—I reckon they should match navigator.language rather than the app language.

It seems to me that for Intl.DateTimeFormat specifically, using the app language is fairly definitely wrong, and to use either the regional preferences language or navigator.language would reasonable courses of action. If it’s navigator.language, then there is no fingerprinting increase. (And indeed perhaps a slight fingerprinting reduction if everything switches from using app language to using navigator.language, unless there are other places where app language is still exposed?) I have no idea how often navigator.language and regional preferences language match, or which people would tend to prefer, or whether it would be a particularly bad thing for different Intl formatters to default to different locales. For me, both are en-AU (while app language is en-US).

Still trying to take a look at this but currently a bit overloaded, triaging in the meantime...

Severity: normal → S3
Priority: -- → P2

Can you meanwhile please add a note like "NOTE, dates are in US MM/DD/YYYY format" or similar to that page?

Assignee: nobody → gijskruitbosch+bugs
Status: NEW → ASSIGNED

(In reply to David Balažic from comment #30)

Can you meanwhile please add a note like "NOTE, dates are in US MM/DD/YYYY format" or similar to that page?

They're not necessarily, the format depends on the browser locale, and the code doing the rendering is not easily able to check this.

I think as a stopgap we should just swap the UTC date (which includes a 3-letter month abbreviation and a 3-letter day abbreviation) that is already in the tooltip, so that's the immediately visible thing.

Pushed by gijskruitbosch@gmail.com:
https://hg.mozilla.org/integration/autoland/rev/4bc970b7440a
show UTC timestamps with month names in the immediately visible label on about:certificate to avoid confusion around date formats, r=johannh
Status: ASSIGNED → RESOLVED
Closed: 3 years ago
Resolution: --- → FIXED
Target Milestone: --- → 86 Branch
Flags: needinfo?(jhofmann)
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: