// Function for SASL security layer negotiation after // authorization completes. // // Returns null for failure, Base64 encoded string on // success. private static 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; int newOffset; Span <byte> unwrappedChallenge; try { len = clientContext.Unwrap(input, out newOffset, out _); unwrappedChallenge = input.AsSpan(newOffset, len); } 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". We verify that the server offers // option to use no security layer and negotiate that if // possible. if (unwrappedChallenge.Length != 4 || (unwrappedChallenge[0] & 1) != 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. // // So now this contructs the "wrapped" response. // let MakeSignature figure out length of output byte[]? output = null; try { len = clientContext.Wrap(_saslNoSecurtyLayerToken, ref output, false); } catch (Win32Exception) { // any encrypt failure is an auth failure return(null); } // return Base64 encoded string of signed payload return(Convert.ToBase64String(output, 0, len)); }