Description
Background and motivation
The NegotiateAuthentication
API (#69920) was added in .NET 7. It exposes functionality for Negotiate, NTLM and Kerberos authentication. It's implemented as a wrapper over GSSAPI (Unix), SSPI (Windows), and there's managed NTLM implementation for other platforms (Android, tvOS) where native API is not available. The initial API shape was driven by the goal of removing reflection access to internal NTAuthentication
class, with focus on meeting the needs of email protocols (SASL in context of IMAP, SMTP), SQL protocols (SQL Server and PostgreSQL), client-side HTTP, and server-side HTTP in ASP.NET.
One omission in the original proposal and its later updates are the GetMIC
and VerifyMIC
operations defined in GSSAPI (https://datatracker.ietf.org/doc/html/rfc2743). These APIs are not used in any of the scenarios above, but they are needed for more specialized protocols, like the NegotiateStream. It is thus desirable to expose them for public use as well.
The operations implemented by the API are generating a "message integrity code" on one side of the communication protocol and verifying it on the other side. It is usually implemented as cryptographic signing operation with a negotiated key.
API Proposal
namespace System.Net.Security;
public sealed class NegotiateAuthentication : IDisposable
{
/// <summary>
/// Computes the message integrity check of a given message.
/// </summary>
/// <param name="message">Input message for MIC calculation.</param>
/// <param name="signature">Buffer writer where the MIC is written.</param>
/// <remarks>
/// Implements the GSSAPI GetMIC operation.
///
/// The method modifies the internal state and may update sequence numbers depending on the
/// selected algorithm. Two successive invocations thus don't produce the same result and
/// it's important to carefully pair GetMIC and VerifyMIC calls on the both sides of the
/// authenticated session.
/// </remarks>
public void ComputeIntegrityCheck(ReadOnlySpan<byte> message, IBufferWriter<byte> signature);
/// <summary>
/// Verifies the message integrity check of a given message.
/// </summary>
/// <param name="message">Input message for MIC calculation.</param>
/// <param name="signature">MIC to be verified.</param>
/// <returns>For successfully verified MIC, the method returns true.</returns>
/// <remarks>
/// Implements the GSSAPI VerifyMIC operation.
///
/// The method modifies the internal state and may update sequence numbers depending on the
/// selected algorithm. Two successive invocations thus don't produce the same result and
/// it's important to carefully pair GetMIC and VerifyMIC calls on the both sides of the
/// authenticated session.
/// </remarks>
public bool VerifyIntegrityCheck(ReadOnlySpan<byte> message, ReadOnlySpan<byte> signature);
}
API Usage
// Client:
var signatureBuffer = new ArrayBufferWriter<byte>();
negotiateAuthentication.ComputeIntegrityCheck(message, signatureBuffer);
// Send (message, signatureSize: signatureBuffer.WrittenBytes, signatureSpan: signatureBuffer.WrittenSpan) to server
// Server:
// Reconstruct (message, signatureSize, signatureSpan) from the wire format
if (!negotiateAuthentication.VerifyIntegrityCheck(message, signatureSpan))
throw new FormatException("The message has been altered");
// Process the message
Alternative Designs
No response
Risks
No response