kerberos-sspi authentication on windows with extended protection does not work. (Enable Extended Protection (channel and service binding) for Kerberos SSPI authentication)
Categories
(Core :: Networking, defect, P2)
Tracking
()
People
(Reporter: kc, Assigned: mkaply)
References
(Blocks 1 open bug)
Details
(Whiteboard: [necko-triaged][ntlm][necko-priority-next])
Attachments
(9 files)
|
899 bytes,
application/zip
|
Details | |
|
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
48 bytes,
text/x-phabricator-request
|
phab-bot
:
approval-mozilla-beta+
|
Details | Review |
|
48 bytes,
text/x-phabricator-request
|
phab-bot
:
approval-mozilla-beta+
|
Details | Review |
|
48 bytes,
text/x-phabricator-request
|
phab-bot
:
approval-mozilla-esr153+
|
Details | Review |
|
48 bytes,
text/x-phabricator-request
|
phab-bot
:
approval-mozilla-esr153+
|
Details | Review |
|
48 bytes,
text/x-phabricator-request
|
phab-bot
:
approval-mozilla-esr140+
|
Details | Review |
|
48 bytes,
text/x-phabricator-request
|
phab-bot
:
approval-mozilla-esr140+
|
Details | Review |
Updated•10 years ago
|
Comment 2•9 years ago
|
||
Comment 3•9 years ago
|
||
| Assignee | ||
Comment 4•6 years ago
|
||
Documentation is here:
https://bugzilla.mozilla.org/show_bug.cgi?id=1179722 (I think)
Here's another detailed scenario:
https://support.mozilla.org/en-US/questions/1296796
chrome added this support in 51.
Comment 5•5 years ago
|
||
Just ran into this problem while trying to enable the ExtendedProtectionTokenCheck setting on an ADFS that was used for authentication for one of our internal web services. Though our Chrome users had no problem with it, FireFox users could no longer authenticate, so we had to disable the setting again, unfortunately.
This is an important security feature for hardening the authentication interaction. Please, could someone of the developers take a closer look and try to tackle this issue?
(In reply to Johan Corveleyn from comment #5)
Just ran into this problem while trying to enable the ExtendedProtectionTokenCheck setting on an ADFS that was used for authentication for one of our internal web services. Though our Chrome users had no problem with it, FireFox users could no longer authenticate, so we had to disable the setting again, unfortunately.
This is an important security feature for hardening the authentication interaction. Please, could someone of the developers take a closer look and try to tackle this issue?
Hi Johan,
Did you set 'ExtendedProtectionTokenCheck ' from None to Allow or from Allow to Require?
This setting is here set to "Allow" and gives no authentication issues.
Did you install the following security patch?
Maybe related to the issue you described, we enabled a security patch (https://support.microsoft.com/nl-nl/topic/managing-deployment-of-kerberos-s4u-changes-for-cve-2020-17049-569d60b7-3267-e2b0-7d9b-e46d770332ab) and perform the second step (set the registerkey 'PerformTicketSignature' to 1), after some time our Firefox users cannot signin anymore into sites through ADFS.
| Assignee | ||
Comment 7•5 years ago
|
||
Here's where the patch went in for Chrome - https://bugs.chromium.org/p/chromium/issues/detail?id=270219#c66
Here's the actual patchset:
https://codereview.chromium.org/1408433006/#ps1
Unfortunately I pasted the wrong thing in my comment and I can't find the documentation anymore.
I'm not sure about prioritization, but I'll put this on folks radar.
Can anyone seeing this tell me how pervasive this is? Like do a lot of people use this and can't use Firefox?
| Assignee | ||
Comment 8•5 years ago
|
||
The specific SSPI change in question for Chrome is here:
https://codereview.chromium.org/1408433006/patch/100001/110039
I think this is the documentation
https://msrc-blog.microsoft.com/2009/12/08/extended-protection-for-authentication/
https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/6b733b95-3fd9-4ad5-ba4f-28e548db1c24?redirectedfrom=MSDN
https://docs.microsoft.com/en-us/windows/win32/api/sspi/ns-sspi-sec_channel_bindings?redirectedfrom=MSDN
(In reply to Mike Kaply [:mkaply] from comment #7)
Here's where the patch went in for Chrome - https://bugs.chromium.org/p/chromium/issues/detail?id=270219#c66
Here's the actual patchset:
https://codereview.chromium.org/1408433006/#ps1
Unfortunately I pasted the wrong thing in my comment and I can't find the documentation anymore.
I'm not sure about prioritization, but I'll put this on folks radar.
Can anyone seeing this tell me how pervasive this is? Like do a lot of people use this and can't use Firefox?
This is the combination in our environment:
- Firefox installed on a domain-joined pc
- ADFS server configured in the about:config setting : Network.automatic-ntlm-auth.trusted-uris
- "Mozilla/5.0" is added (default(?)) in ADFS WIASupportedUserAgents
- 2nd phase of the patch "cve-2020-17049" installed on all DC's (https://support.microsoft.com/nl-nl/topic/managing-deployment-of-kerberos-s4u-changes-for-cve-2020-17049-569d60b7-3267-e2b0-7d9b-e46d770332ab)
| Assignee | ||
Updated•5 years ago
|
Comment 10•5 years ago
|
||
(In reply to Rende from comment #6, and Mike Kaply)
Hi Johan,
Did you set 'ExtendedProtectionTokenCheck ' from None to Allow or from Allow to Require?
This setting is here set to "Allow" and gives no authentication issues.Did you install the following security patch?
Maybe related to the issue you described, we enabled a security patch (https://support.microsoft.com/nl-nl/topic/managing-deployment-of-kerberos-s4u-changes-for-cve-2020-17049-569d60b7-3267-e2b0-7d9b-e46d770332ab) and perform the second step (set the registerkey 'PerformTicketSignature' to 1), after some time our Firefox users cannot signin anymore into sites through ADFS.
Sorry for the late response. I have received some more details from our sysadmin:
'ExtendedProtectionTokenCheck ' was changed from None to Allow (the Require option has not been tested)
The security patch mentioned was installed, but the registry keys are not created.
These two bullets in Rende's list also apply to our situation:
- Firefox installed on a domain-joined pc
- "Mozilla/5.0" is added (default(?)) in ADFS WIASupportedUserAgents
Comment 11•5 years ago
|
||
I can confirm this bug still exists, and that as per the timings of the CVE, this setting is now set to enforced, with no way around it: https://support.microsoft.com/en-us/topic/kb4598347-managing-deployment-of-kerberos-s4u-changes-for-cve-2020-17049-569d60b7-3267-e2b0-7d9b-e46d770332ab
In our case it was enforcing kerberos auth only on the ADFS server that resulted in Firefox users getting broken authentication. The firefox client simply sits on the adfs page with the response in the URL in this format:
It would be nice to allow our firefox preferring folks to be able to use their preferred browser again - we use ADFS for authenticating various systems. They currently have to use Chrome or Edge Chromium. The thing that makes me especially sad is that this even works in IE.
Happy to help test and updates to this if someone wants to progress this one.
| Assignee | ||
Comment 13•5 years ago
|
||
(In reply to Dragana Damjanovic [:dragana] from comment #12)
Mike, should we change priority for this?
Definitely. I tried to get some traction on it earlier this year but couldn't find the right people.
Comment 14•5 years ago
|
||
Jens, can you find someone to look into this? We might be able to reuse most of the code from bug 573043, but I have not look very closely.
Comment 16•4 years ago
|
||
Hey folks, any movement on this? In addition to our internal users experiencing this issue, we develop a web app and have now had reports from customers of similar issues with Firefox + ADFS, and have sadly had to let them know of this bug and that they'll need to use a browser other than Firefox if authenticating against ADFS. As I say, very happy to help in any testing, as would a number of our devs who greatly prefer Firefox.
Comment 17•4 years ago
|
||
We are also running into this at my workplace. A specific site works fine in Chrome but does not work at all in Firefox. Would be really sad to recommend people to switch.
I'd love to help testing if I can be of assistance.
Comment 18•4 years ago
|
||
I am also running into this at my workplace. +1 for fixing this issue.
Comment 19•4 years ago
|
||
Martinho offered to take a look.
Comment 20•4 years ago
|
||
Hi all,
Can anyone provide me access to or point to an example server (ideally pre-configured) to replicate this issue?
Also a mozregression range may be useful (?)
Updated•3 years ago
|
Comment 21•2 years ago
|
||
I have experienced this similar issue with Firefox after changing the ADFS SSL certificate to a SHA384 certificate. It seems like the issue was resolved for SHA256 SSL cert on the ADFS server.
Comment 22•2 years ago
|
||
(In reply to Dragana Damjanovic [:dragana] from comment #14)
Jens, can you find someone to look into this? We might be able to reuse most of the code from bug 573043, but I have not look very closely.
Looking at that code, it seems exactly what has to happen!
Comment 23•2 years ago
|
||
(In reply to Mervyn Morris from comment #21)
I have experienced this similar issue with Firefox after changing the ADFS SSL certificate to a SHA384 certificate. It seems like the issue was resolved for SHA256 SSL cert on the ADFS server.
Hi, could you try to capture a http log that shows this issue?
In about:logging, please select Logging to file and send the log file to necko@mozilla.com.
Thanks.
Comment 24•2 years ago
|
||
(In reply to Kershaw Chang [:kershaw] from comment #23)
(In reply to Mervyn Morris from comment #21)
I have experienced this similar issue with Firefox after changing the ADFS SSL certificate to a SHA384 certificate. It seems like the issue was resolved for SHA256 SSL cert on the ADFS server.
Hi, could you try to capture a http log that shows this issue?
Inabout:logging, please selectLogging to fileand send the log file to necko@mozilla.com.
Thanks.
Good day,
I do apologize but because this was our production environment we were forced to revert to a SHA256 SSL Cert which has allowed functionality for at least another year. I wouldn't be able to reproduce the issue at this moment.
Comment 25•2 years ago
|
||
Probably because the NTLM code for channel binding uses a fixed size for the hash; https://hg.mozilla.org/integration/mozilla-inbound/rev/e01dbdb4c7e1#l1.125
It's not necessarily related to this specific issue.
Comment 26•1 year ago
|
||
We will try to fix this in bug 1895277.
| Assignee | ||
Comment 27•2 months ago
|
||
I asked Claude to dig into the code here after a new report came in on the enterprise mailing list. Posting its analysis below unedited — I think it makes a good case that this shouldn't have been duped.
The comment:
[Analysis generated by Claude (Opus 5), reviewed but not edited by :mkaply. Code references verified against mozilla-central and the 140/153 ESR branches.]
This bug appears to have been duplicated against bug 1895277 in error. The two bugs describe different defects that present identically from a user's perspective, and only one of them was fixed.
Bug 1895277 corrected a hardcoded SHA-256 assumption in the channel binding token hash so that it now follows the certificate's signature algorithm. That code path is reached only when a server certificate has been supplied to the auth module. In nsAuthSSPI::GetNextToken, the SECBUFFER_CHANNEL_BINDINGS buffer is constructed only under mCertDERLength > 0:
https://searchfox.org/mozilla-central/source/extensions/auth/nsAuthSSPI.cpp#336
There is exactly one caller that ever populates that field. nsHttpNTLMAuth::GenerateCredentials retrieves securityInfo->GetServerCert() and passes the DER as the input token on the first GetNextToken() call:
https://searchfox.org/mozilla-central/source/netwerk/protocol/http/nsHttpNTLMAuth.cpp#318
nsHttpNegotiateAuth::GenerateCredentials does not call GetSecurityInfo at any point. It base64-decodes the challenge and passes only that token through:
https://searchfox.org/mozilla-central/source/extensions/auth/nsHttpNegotiateAuth.cpp#449
The consequence is that on the Negotiate path, InitializeSecurityContextW is invoked with no channel bindings buffer at all — for Kerberos and for NTLM negotiated inside SPNEGO alike. There is no CBT present for the hash algorithm fix to apply to. The same holds on Linux and macOS, where nsAuthGSSAPI passes GSS_C_NO_CHANNEL_BINDINGS explicitly:
https://searchfox.org/mozilla-central/source/extensions/auth/nsAuthGSSAPI.cpp#426
The most likely explanation for the successful verification in bug 1895277 is that those reporters were authenticating over NTLM rather than Negotiate. That path has had working channel binding since bug 573043 landed in 2010, and was broken only for SHA-384 and SHA-512 certificates until 1895277. Comment 9 of this bug supports that reading for at least one reporter here: their ADFS host was configured in network.automatic-ntlm-auth.trusted-uris, which routes to the NTLM authenticator, not the Negotiate one.
This bug's summary — "Enable Extended Protection (channel and service binding) for Kerberos SSPI authentication" — remains an accurate description of unimplemented work. Comment 1, from 2015, identified the distinction correctly at the time: "This is fixed for ntlm but seems not to work for sspi kerberos."
A partial workaround exists for affected deployments. Negotiate outranks NTLM in the challenge selection logic:
https://searchfox.org/mozilla-central/source/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp#514
Removing the affected hosts from network.negotiate-auth.trusted-uris and adding them to network.automatic-ntlm-auth.trusted-uris causes nsHttpNegotiateAuth::ChallengeReceived to return NS_ERROR_ABORT, and the provider falls through to the NTLM challenge, which does emit a valid tls-server-end-point CBT. network.auth.force-generic-ntlm must remain false, as the internal NTLM module has no channel binding support. This trades Kerberos for NTLMv2, but the channel binding is present, so the relay attack that Extended Protection defends against remains mitigated. It is a stopgap, not a resolution.
Recommendation: reopen this bug rather than filing a new one. The Chrome reference implementation links in comments 7 and 8 remain the relevant prior art, and the reporter history and CC list here are substantial.
| Assignee | ||
Comment 28•2 months ago
|
||
Confirmed this wasn't in 1895277.
Reopening and I'll attach a patch.
| Assignee | ||
Comment 30•2 months ago
|
||
The SEC_CHANNEL_BINDINGS buffer was only ever built on continuation calls. That
is sufficient for raw NTLM, whose channel binding travels in message 3, but
SPNEGO carries the AP-REQ in the very first token, so Kerberos needs the
bindings from the initial call on and never received them.
Move the token construction into a helper and attach it whenever a certificate
is available, building the input buffer descriptor up front so it can be passed
with no accompanying token. Keep the certificate for the lifetime of the
sequence instead of freeing it after first use, so every leg of a multi-leg
exchange carries the bindings.
The exemption for PACKAGE_TYPE_NTLM covers the sys-ntlm module only, which
keeps behaving exactly as it does today. NTLM negotiated inside SPNEGO runs
under PACKAGE_TYPE_NEGOTIATE and will now carry bindings from the first call:
that is the main behaviour change here and the one worth reviewing closely,
since raw NTLM is deliberately untouched.
On its own this commit changes nothing, because no caller supplies a
certificate on the Negotiate path until the next one.
Updated•2 months ago
|
| Assignee | ||
Comment 31•2 months ago
|
||
nsHttpNegotiateAuth never retrieved the server certificate, so nsAuthSSPI had
nothing to build a channel binding token from and Negotiate authentication
never sent one. Servers with Extended Protection set to Require reject that,
which is why Kerberos SSO fails against ADFS and Exchange OWA where Chrome and
Edge succeed. nsHttpNTLMAuth is the only caller that has ever supplied a
certificate.
GenerateCredentials runs on a background thread, so the certificate is
collected on the main thread in GenerateCredentialsAsync, and only for a
challenge that carries no token of its own. That is the first call of a
sequence, and the only call where nsAuthSSPI::GetNextToken expects a
certificate in place of the input token.
Proxy auth is excluded because the channel's security info describes the origin
server rather than the proxy. Extended Protection for proxies needs the proxy's
own certificate and is left for a follow-up.
network.auth.negotiate_channel_binding backs the change out.
| Assignee | ||
Comment 32•2 months ago
|
||
I've had two customers that have this problem test my try build and it fixed it for them.
Comment 33•1 month ago
|
||
A patch has been attached on this bug, which was already closed. Filing a separate bug will ensure better tracking. If this was not by mistake and further action is needed, please alert the appropriate party. (Or: if the patch doesn't change behavior -- e.g. landing a test case, or fixing a typo -- then feel free to disregard this message)
| Assignee | ||
Updated•1 month ago
|
Comment 34•1 month ago
|
||
| Assignee | ||
Comment 35•1 month ago
|
||
[Tracking Requested - why for this release]: We have a customer that really wants this on 140 if possible.
Comment 36•1 month ago
|
||
| bugherder | ||
https://hg.mozilla.org/mozilla-central/rev/0fecd717e230
https://hg.mozilla.org/mozilla-central/rev/2039048f8f7d
| Assignee | ||
Comment 37•1 month ago
|
||
The SEC_CHANNEL_BINDINGS buffer was only ever built on continuation calls. That
is sufficient for raw NTLM, whose channel binding travels in message 3, but
SPNEGO carries the AP-REQ in the very first token, so Kerberos needs the
bindings from the initial call on and never received them.
Move the token construction into a helper and attach it whenever a certificate
is available, building the input buffer descriptor up front so it can be passed
with no accompanying token. Keep the certificate for the lifetime of the
sequence instead of freeing it after first use, so every leg of a multi-leg
exchange carries the bindings.
The exemption for PACKAGE_TYPE_NTLM covers the sys-ntlm module only, which
keeps behaving exactly as it does today. NTLM negotiated inside SPNEGO runs
under PACKAGE_TYPE_NEGOTIATE and will now carry bindings from the first call:
that is the main behaviour change here and the one worth reviewing closely,
since raw NTLM is deliberately untouched.
On its own this commit changes nothing, because no caller supplies a
certificate on the Negotiate path until the next one.
Original Revision: https://phabricator.services.mozilla.com/D316807
Updated•1 month ago
|
Comment 38•1 month ago
|
||
firefox-beta Uplift Approval Request
- User impact if declined/Reason for urgency: This is important for a specific enterprise customer.
It has no impact on other code that doesn't go down this codepath.
- Code covered by automated testing?: no
- Fix verified in Nightly?: yes
- Needs manual QE testing?: no
- Steps to reproduce for manual QE testing:
- Risk associated with taking this patch: low
- Explanation of risk level: Adds a new path controlled by a preference.
- String changes made/needed?: None
- Is Android affected?: no
| Assignee | ||
Comment 39•1 month ago
|
||
nsHttpNegotiateAuth never retrieved the server certificate, so nsAuthSSPI had
nothing to build a channel binding token from and Negotiate authentication
never sent one. Servers with Extended Protection set to Require reject that,
which is why Kerberos SSO fails against ADFS and Exchange OWA where Chrome and
Edge succeed. nsHttpNTLMAuth is the only caller that has ever supplied a
certificate.
GenerateCredentials runs on a background thread, so the certificate is
collected on the main thread in GenerateCredentialsAsync, and only for a
challenge that carries no token of its own. That is the first call of a
sequence, and the only call where nsAuthSSPI::GetNextToken expects a
certificate in place of the input token.
Proxy auth is excluded because the channel's security info describes the origin
server rather than the proxy. Extended Protection for proxies needs the proxy's
own certificate and is left for a follow-up.
network.auth.negotiate_channel_binding backs the change out.
Original Revision: https://phabricator.services.mozilla.com/D316808
| Assignee | ||
Comment 40•1 month ago
|
||
The SEC_CHANNEL_BINDINGS buffer was only ever built on continuation calls. That
is sufficient for raw NTLM, whose channel binding travels in message 3, but
SPNEGO carries the AP-REQ in the very first token, so Kerberos needs the
bindings from the initial call on and never received them.
Move the token construction into a helper and attach it whenever a certificate
is available, building the input buffer descriptor up front so it can be passed
with no accompanying token. Keep the certificate for the lifetime of the
sequence instead of freeing it after first use, so every leg of a multi-leg
exchange carries the bindings.
The exemption for PACKAGE_TYPE_NTLM covers the sys-ntlm module only, which
keeps behaving exactly as it does today. NTLM negotiated inside SPNEGO runs
under PACKAGE_TYPE_NEGOTIATE and will now carry bindings from the first call:
that is the main behaviour change here and the one worth reviewing closely,
since raw NTLM is deliberately untouched.
On its own this commit changes nothing, because no caller supplies a
certificate on the Negotiate path until the next one.
Original Revision: https://phabricator.services.mozilla.com/D316807
Updated•1 month ago
|
Comment 41•1 month ago
|
||
firefox-esr153 Uplift Approval Request
- User impact if declined/Reason for urgency: This is important for a specific enterprise customer.
It has no impact on other code that doesn't go down this codepath.
- Code covered by automated testing?: no
- Fix verified in Nightly?: yes
- Needs manual QE testing?: no
- Steps to reproduce for manual QE testing:
- Risk associated with taking this patch: low
- Explanation of risk level: Adds a new path controlled by a preference.
- String changes made/needed?: None
- Is Android affected?: no
| Assignee | ||
Comment 42•1 month ago
|
||
nsHttpNegotiateAuth never retrieved the server certificate, so nsAuthSSPI had
nothing to build a channel binding token from and Negotiate authentication
never sent one. Servers with Extended Protection set to Require reject that,
which is why Kerberos SSO fails against ADFS and Exchange OWA where Chrome and
Edge succeed. nsHttpNTLMAuth is the only caller that has ever supplied a
certificate.
GenerateCredentials runs on a background thread, so the certificate is
collected on the main thread in GenerateCredentialsAsync, and only for a
challenge that carries no token of its own. That is the first call of a
sequence, and the only call where nsAuthSSPI::GetNextToken expects a
certificate in place of the input token.
Proxy auth is excluded because the channel's security info describes the origin
server rather than the proxy. Extended Protection for proxies needs the proxy's
own certificate and is left for a follow-up.
network.auth.negotiate_channel_binding backs the change out.
Original Revision: https://phabricator.services.mozilla.com/D316808
Updated•1 month ago
|
Updated•1 month ago
|
Updated•1 month ago
|
Comment 43•1 month ago
|
||
| uplift | ||
| Assignee | ||
Comment 44•1 month ago
|
||
The SEC_CHANNEL_BINDINGS buffer was only ever built on continuation calls. That
is sufficient for raw NTLM, whose channel binding travels in message 3, but
SPNEGO carries the AP-REQ in the very first token, so Kerberos needs the
bindings from the initial call on and never received them.
Move the token construction into a helper and attach it whenever a certificate
is available, building the input buffer descriptor up front so it can be passed
with no accompanying token. Keep the certificate for the lifetime of the
sequence instead of freeing it after first use, so every leg of a multi-leg
exchange carries the bindings.
The exemption for PACKAGE_TYPE_NTLM covers the sys-ntlm module only, which
keeps behaving exactly as it does today. NTLM negotiated inside SPNEGO runs
under PACKAGE_TYPE_NEGOTIATE and will now carry bindings from the first call:
that is the main behaviour change here and the one worth reviewing closely,
since raw NTLM is deliberately untouched.
On its own this commit changes nothing, because no caller supplies a
certificate on the Negotiate path until the next one.
Original Revision: https://phabricator.services.mozilla.com/D316807
Updated•1 month ago
|
Comment 45•1 month ago
|
||
firefox-esr140 Uplift Approval Request
- User impact if declined/Reason for urgency: This is important for a specific enterprise customer.
It has no impact on other code that doesn't go down this codepath.
- Code covered by automated testing?: no
- Fix verified in Nightly?: yes
- Needs manual QE testing?: no
- Steps to reproduce for manual QE testing:
- Risk associated with taking this patch: low
- Explanation of risk level: Adds a new path controlled by a preference.
- String changes made/needed?: None
- Is Android affected?: no
| Assignee | ||
Comment 46•1 month ago
|
||
nsHttpNegotiateAuth never retrieved the server certificate, so nsAuthSSPI had
nothing to build a channel binding token from and Negotiate authentication
never sent one. Servers with Extended Protection set to Require reject that,
which is why Kerberos SSO fails against ADFS and Exchange OWA where Chrome and
Edge succeed. nsHttpNTLMAuth is the only caller that has ever supplied a
certificate.
GenerateCredentials runs on a background thread, so the certificate is
collected on the main thread in GenerateCredentialsAsync, and only for a
challenge that carries no token of its own. That is the first call of a
sequence, and the only call where nsAuthSSPI::GetNextToken expects a
certificate in place of the input token.
Proxy auth is excluded because the channel's security info describes the origin
server rather than the proxy. Extended Protection for proxies needs the proxy's
own certificate and is left for a follow-up.
network.auth.negotiate_channel_binding backs the change out.
Original Revision: https://phabricator.services.mozilla.com/D316808
Updated•1 month ago
|
Updated•1 month ago
|
Updated•1 month ago
|
Updated•1 month ago
|
Updated•1 month ago
|
Comment 47•1 month ago
|
||
| uplift | ||
Updated•1 month ago
|
Updated•1 month ago
|
Comment 48•1 month ago
|
||
| uplift | ||
Updated•1 month ago
|
Description
•