Closed Bug 1179722 Opened 11 years ago Closed 1 month ago

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)

38 Branch
x86
Unspecified
defect

Tracking

()

RESOLVED FIXED
155 Branch
Tracking Status
firefox-esr140 154+ fixed
firefox-esr153 --- fixed
firefox154 --- fixed
firefox155 --- fixed

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
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
Attached file firefox_log.zip —
User Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.89 Safari/537.36 Steps to reproduce: On our site we use kerberos authentication to our intranet websites. This works ok when I enable NTLM or use the gssapi32.dll from MIT kerberos but not with sspi on windows. the output from negotiateauth is attached for a session with extended protection on and off. Also when i disable the extended protection it works see: https://support.microsoft.com/en-us/kb/976918/en-us Actual results: I get a popup where i have to logon to the website. Expected results: It should have logged me in sso.
This is fixed for ntlm but seems not to work for sspi kerberos. https://bugzilla.mozilla.org/show_bug.cgi?id=573043
Component: Untriaged → Security
Hardware: Unspecified → x86
Component: Security → Networking
Product: Firefox → Core
Whiteboard: [necko-backlog][ntlm]
Priority: -- → P1
Priority: P1 → P3

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.

Status: UNCONFIRMED → NEW
Ever confirmed: true

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.

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?

(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:

(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

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:

https://adfsservername.domain.com/adfs/ls/wia?SAMLRequest=CLOBBER&RelayState=%2F&SigAlg=http%3A%2F%2Fwww.w3.org%2F2001%2F04%2Fxmldsig-more%23rsa-sha256&Signature=CLOBBER&client-request-id=CLOBBER

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.

Mike, should we change priority for this?

Flags: needinfo?(mozilla)

(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.

Flags: needinfo?(mozilla)

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.

Flags: needinfo?(jstutte)

Christoph, can you?

Flags: needinfo?(jstutte) → needinfo?(ckerschb)

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.

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.

I am also running into this at my workplace. +1 for fixing this issue.

Martinho offered to take a look.

Assignee: nobody → bugs
Status: NEW → ASSIGNED
Flags: needinfo?(ckerschb)
Priority: P3 → P2
Assignee: bugs → eguloien

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 (?)

See Also: → 1781743
Severity: normal → S3
Assignee: edgul → nobody
Status: ASSIGNED → NEW

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.

(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!

(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.

Flags: needinfo?(msmorris)
Whiteboard: [necko-backlog][ntlm] → [necko-triaged][ntlm][necko-priority-next]

(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?
In about:logging, please select Logging to file and 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.

Flags: needinfo?(msmorris)

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.

We will try to fix this in bug 1895277.

Status: NEW → RESOLVED
Closed: 1 year ago
Duplicate of bug: 1895277
Resolution: --- → DUPLICATE
See Also: 1781743 →

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.

Confirmed this wasn't in 1895277.

Reopening and I'll attach a patch.

Duplicate of this bug: 2060492

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.

Assignee: nobody → mozilla

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.

I've had two customers that have this problem test my try build and it fixed it for them.

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)

Status: RESOLVED → REOPENED
No longer duplicate of bug: 1895277
Resolution: DUPLICATE → ---
See Also: → 2062258
See Also: → 2062260
See Also: → 1781743
See Also: → 2062271

[Tracking Requested - why for this release]: We have a customer that really wants this on 140 if possible.

Status: REOPENED → RESOLVED
Closed: 1 year ago → 1 month ago
Resolution: --- → FIXED
Target Milestone: --- → 155 Branch

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

Attachment #9625210 - Flags: approval-mozilla-beta?

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
Attachment #9625211 - Flags: approval-mozilla-beta?

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

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

Attachment #9625212 - Flags: approval-mozilla-esr153?

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
Attachment #9625213 - Flags: approval-mozilla-esr153?

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

Attachment #9625210 - Flags: approval-mozilla-beta? → approval-mozilla-beta+
Attachment #9625211 - Flags: approval-mozilla-beta? → approval-mozilla-beta+

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

Attachment #9625289 - Flags: approval-mozilla-esr140?

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
Attachment #9625290 - Flags: approval-mozilla-esr140?

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

Attachment #9625212 - Flags: approval-mozilla-esr153? → approval-mozilla-esr153+
Attachment #9625213 - Flags: approval-mozilla-esr153? → approval-mozilla-esr153+
Attachment #9625289 - Flags: approval-mozilla-esr140? → approval-mozilla-esr140+
Attachment #9625290 - Flags: approval-mozilla-esr140? → approval-mozilla-esr140+
QA Whiteboard: [qa-triage-done-c155/b154]
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: