private string GetSecurityLayerOutgoingBlob(string challenge, NTAuthentication clientContext) { int num; if (challenge == null) { return(null); } byte[] buffer = Convert.FromBase64String(challenge); try { num = clientContext.VerifySignature(buffer, 0, buffer.Length); } catch (Win32Exception) { return(null); } if (((num < 4) || (buffer[0] != 1)) || (((buffer[1] != 0) || (buffer[2] != 0)) || (buffer[3] != 0))) { return(null); } byte[] output = null; try { num = clientContext.MakeSignature(buffer, 0, 4, ref output); } catch (Win32Exception) { return(null); } return(Convert.ToBase64String(output, 0, num)); }
public void NtlmSignatureTest() { FakeNtlmServer fakeNtlmServer = new FakeNtlmServer(s_testCredentialRight); NTAuthentication ntAuth = new NTAuthentication( isServer: false, "NTLM", s_testCredentialRight, "HTTP/foo", ContextFlagsPal.Connection | ContextFlagsPal.InitIntegrity | ContextFlagsPal.Confidentiality, null); DoNtlmExchange(fakeNtlmServer, ntAuth); Assert.True(fakeNtlmServer.IsAuthenticated); // Test MakeSignature on client side and decoding it on server side byte[]? output = null; int len = ntAuth.MakeSignature(s_Hello, 0, s_Hello.Length, ref output); 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); 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, 0, serverSignedMessage.Length); Assert.Equal(s_Hello.Length, len); // NOTE: VerifySignature doesn't return the content on Windows // Assert.Equal(s_Hello, serverSignedMessage.AsSpan(0, len).ToArray()); }
// Function for SASL security layer negotiation after // authorization completes. // // Returns null for failure, Base64 encoded string on // success. private string GetSecurityLayerOutgoingBlob(string challenge, NTAuthentication clientContext) { // must have a security layer challenge if (challenge == null) { return(null); } // "unwrap" challenge byte[] input = Convert.FromBase64String(challenge); int len; try { len = clientContext.VerifySignature(input, 0, input.Length); } catch (Win32Exception) { // any decrypt failure is an auth failure return(null); } // Per RFC 2222 Section 7.2.2: // the client should then expect the server to issue a // token in a subsequent challenge. The client passes // this token to GSS_Unwrap and interprets the first // octet of cleartext as a bit-mask specifying the // security layers supported by the server and the // second through fourth octets as the maximum size // output_message to send to the server. // Section 7.2.3 // The security layer and their corresponding bit-masks // are as follows: // 1 No security layer // 2 Integrity protection // Sender calls GSS_Wrap with conf_flag set to FALSE // 4 Privacy protection // Sender calls GSS_Wrap with conf_flag set to TRUE // // Exchange 2007 and our client only support // "No security layer". Therefore verify first byte is value 1 // and the 2nd-4th bytes are value zero since token size is not // applicable when there is no security layer. if (len < 4 || // expect 4 bytes input[0] != 1 || // first value 1 input[1] != 0 || // rest value 0 input[2] != 0 || input[3] != 0) { return(null); } // Continuing with RFC 2222 section 7.2.2: // The client then constructs data, with the first octet // containing the bit-mask specifying the selected security // layer, the second through fourth octets containing in // network byte order the maximum size output_message the client // is able to receive, and the remaining octets containing the // authorization identity. // // So now this contructs the "wrapped" response. The response is // payload is identical to the received server payload and the // "authorization identity" is not supplied as it is unnecessary. // let MakeSignature figure out length of output byte[] output = null; try { len = clientContext.MakeSignature(input, 0, 4, ref output); } catch (Win32Exception) { // any encrypt failure is an auth failure return(null); } // return Base64 encoded string of signed payload return(Convert.ToBase64String(output, 0, len)); }
// Function for SASL security layer negotiation after // authorization completes. // // Returns null for failure, Base64 encoded string on // success. private string GetSecurityLayerOutgoingBlob(string challenge, NTAuthentication clientContext) { // must have a security layer challenge if (challenge == null) return null; // "unwrap" challenge byte[] input = Convert.FromBase64String(challenge); int len; try { len = clientContext.VerifySignature(input, 0, input.Length); } catch (Win32Exception) { // any decrypt failure is an auth failure return null; } // Per RFC 2222 Section 7.2.2: // the client should then expect the server to issue a // token in a subsequent challenge. The client passes // this token to GSS_Unwrap and interprets the first // octet of cleartext as a bit-mask specifying the // security layers supported by the server and the // second through fourth octets as the maximum size // output_message to send to the server. // Section 7.2.3 // The security layer and their corresponding bit-masks // are as follows: // 1 No security layer // 2 Integrity protection // Sender calls GSS_Wrap with conf_flag set to FALSE // 4 Privacy protection // Sender calls GSS_Wrap with conf_flag set to TRUE // // Exchange 2007 and our client only support // "No security layer". Therefore verify first byte is value 1 // and the 2nd-4th bytes are value zero since token size is not // applicable when there is no security layer. if (len < 4 || // expect 4 bytes input[0] != 1 || // first value 1 input[1] != 0 || // rest value 0 input[2] != 0 || input[3] != 0) { return null; } // Continuing with RFC 2222 section 7.2.2: // The client then constructs data, with the first octet // containing the bit-mask specifying the selected security // layer, the second through fourth octets containing in // network byte order the maximum size output_message the client // is able to receive, and the remaining octets containing the // authorization identity. // // So now this contructs the "wrapped" response. The response is // payload is identical to the received server payload and the // "authorization identity" is not supplied as it is unnecessary. // let MakeSignature figure out length of output byte[] output = null; try { len = clientContext.MakeSignature(input, 0, 4, ref output); } catch (Win32Exception) { // any encrypt failure is an auth failure return null; } // return Base64 encoded string of signed payload return Convert.ToBase64String(output, 0, len); }
// Function for SASL security layer negotiation after // authorization completes. // // Returns null for failure, Base64 encoded string on // success. private string GetSecurityLayerOutgoingBlob( string challenge, NTAuthentication clientContext) { // must have a security layer challenge if (challenge == null) { return(null); } // "unwrap" challenge byte[] input = Convert.FromBase64String(challenge); int len; try { len = clientContext.VerifySignature(input, 0, input.Length); } catch (Win32Exception) { // any decrypt failure is an auth failure return(null); } // Per RFC 2222 Section 7.2.2: // the client should then expect the server to issue a // token in a subsequent challenge. The client passes // this token to GSS_Unwrap and interprets the first // octet of cleartext as a bit-mask specifying the // security layers supported by the server and the // second through fourth octets as the maximum size // output_message to send to the server. // Section 7.2.3 // The security layer and their corresponding bit-masks // are as follows: // 1 No security layer // 2 Integrity protection // Sender calls GSS_Wrap with conf_flag set to FALSE // 4 Privacy protection // Sender calls GSS_Wrap with conf_flag set to TRUE // // Our SmtpClient only supports "No security layer". So, make // sure that the server also supports this. We don't care if the // server also supports other features (Integrity or Privacy). // Therefore verify first bit in first byte is value 1. // We ignore the 2nd-4th bytes since token size is not // applicable when we select no security layer. if (len < 4 || (input[0] & 0x1) != 1) { return(null); } // Continuing with RFC 2222 section 7.2.2: // The client then constructs data, with the first octet // containing the bit-mask specifying the selected security // layer, the second through fourth octets containing in // network byte order the maximum size output_message the client // is able to receive, and the remaining octets containing the // authorization identity. // // Our response back to server is very simple. We select "No security layer". input[0] = 1; // let MakeSignature figure out length of output byte[] output = null; try { len = clientContext.MakeSignature(input, 0, 4, ref output); } catch (Win32Exception) { // any decrypt failure is an auth failure return(null); } // return Base64 encoded string of signed payload return(Convert.ToBase64String(output, 0, len)); }