diff options
author | Filip Navara <navara@emclient.com> | 2022-06-30 15:19:42 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-30 15:19:42 +0300 |
commit | ac9e1f968050fa5f83a81a62c69e3eb0185975f8 (patch) | |
tree | 50a1f5d0d574ec2ab7e01c02f842f6a701e740b5 /src/libraries/System.Net.Security/tests/UnitTests | |
parent | 667812e459b135c14486431e4c7f27e770b987fc (diff) |
Improve interoperability of NTLM encryption/decryption and authentication (#71373)
* Implement NTLM quirk in NegotiateStreamPal.Encrypt/Decrypt
NegotiateStream on non-encrypted connections with NTLM sends the
messages in a special `<signature token><plain text message>` format.
That's not something that gss_wrap/gss_unwrap would produce. It can be
produced through gss_get_mic/gss_verify_mic calls though so let's do
that.
* Remove MakeSignature/VerifySignature from SspiCli interop
The method names were misleading since they wrapped the EncryptMessage
and DecryptMessage native APIs and not the MakeSignature/VerifySignature
APIs that also exist.
* Remove unused sequenceNumber parameters in NegotiateStreamPal.Encrypt/Decrypt
The SSPI / GSSAPI providers keep track of the sequence numbers
themselves.
* Replace NTAuthentication.MakeSignature/VerifySignature with Wrap/Unwrap
This maps directly to the semantics of gss_wrap/gss_unwrap methods
that are used in many specifications. It replaces the misleading name
which in SSPI API is an equivalent of gss_get_mic/gss_verify_mic.
It also fixes the declaration to actually decode the buffers both
on Windows and Unix. In NTLM the content of the message is sealed
and needs to be decoded.
Note that previously on Unix the VerifySignature API didn't decode the
content. On Windows it did decode the content inside a buffer that was
passed as ReadOnlySpan<byte> but it didn't communicate back the offset
of the decoded data.
The SMTP GSSAPI authentication code was thus reading incorrect data.
In case the underlying authentication was Kerberos the data were
not encrypted and they were located at the beginning of the buffer
so it was not an issue. In case the underlying authentication was
NTLM it was looking at the NTLM signature token which luckily
happens to always start with the bytes 01 00 00 00. That exactly
matched the expected value by accident.
* Fix processing of last SMTP GSSAPI token
The last token in the GSSAPI SASL authentication mechanism is a bit
mask that specifies the supported security protections offered by the
server and the maximum token size. The client is supposed to choose
one of the protections and reply back. Relax the check to actually
support servers that offer anything but "no protection". As long
as the server also offers no protection we can choose it.
* Update unit test to use the new Wrap/Unwrap APIs
* Reset NTLM keys after successful Negotiate authentication
Updated the managed NTLM implementation and the fake servers to
implement the specification quirk:
MS-SPNG section 3.2.5.1 NTLM RC4 Key State for MechListMIC and First
Signed Message specifies that the RC4 sealing keys are reset back to
the initial state for the first message.
Since the managed implementation doesn't expose encryption yet it
didn't affect any observable behavior. Likewise the fake servers
didn't need this code path yet.
* Add GSSAPI authentication test to the loopback SMTP server
* Workaround for https://github.com/gssapi/gss-ntlmssp/issues/77
* Expose the confidentiality flag from the native gss_wrap/unwrap APIs
* Allow default credentials for NTLM server-side on Linux/macOS
Diffstat (limited to 'src/libraries/System.Net.Security/tests/UnitTests')
-rw-r--r-- | src/libraries/System.Net.Security/tests/UnitTests/NTAuthenticationTests.cs | 14 |
1 files changed, 5 insertions, 9 deletions
diff --git a/src/libraries/System.Net.Security/tests/UnitTests/NTAuthenticationTests.cs b/src/libraries/System.Net.Security/tests/UnitTests/NTAuthenticationTests.cs index 34c816b867b..da1e4d23e6d 100644 --- a/src/libraries/System.Net.Security/tests/UnitTests/NTAuthenticationTests.cs +++ b/src/libraries/System.Net.Security/tests/UnitTests/NTAuthenticationTests.cs @@ -34,24 +34,20 @@ namespace System.Net.Security.Tests // Test MakeSignature on client side and decoding it on server side byte[]? output = null; - int len = ntAuth.MakeSignature(s_Hello, ref output); + int len = ntAuth.Wrap(s_Hello, ref output, true); Assert.NotNull(output); Assert.Equal(16 + s_Hello.Length, len); // Unseal the content and check it byte[] temp = new byte[s_Hello.Length]; - fakeNtlmServer.Unseal(output.AsSpan(16), temp); + fakeNtlmServer.Unwrap(output, temp); Assert.Equal(s_Hello, temp); - // Check the signature - fakeNtlmServer.VerifyMIC(temp, output.AsSpan(0, 16), sequenceNumber: 0); // Test creating signature on server side and decoding it with VerifySignature on client side byte[] serverSignedMessage = new byte[16 + s_Hello.Length]; - fakeNtlmServer.Seal(s_Hello, serverSignedMessage.AsSpan(16, s_Hello.Length)); - fakeNtlmServer.GetMIC(s_Hello, serverSignedMessage.AsSpan(0, 16), sequenceNumber: 0); - len = ntAuth.VerifySignature(serverSignedMessage); + fakeNtlmServer.Wrap(s_Hello, serverSignedMessage); + len = ntAuth.Unwrap(serverSignedMessage, out int newOffset, out _); Assert.Equal(s_Hello.Length, len); - // NOTE: VerifySignature doesn't return the content on Windows - // Assert.Equal(s_Hello, serverSignedMessage.AsSpan(0, len).ToArray()); + Assert.Equal(s_Hello, serverSignedMessage.AsSpan(newOffset, len).ToArray()); } private void DoNtlmExchange(FakeNtlmServer fakeNtlmServer, NTAuthentication ntAuth) |