Working on comments.

This commit is contained in:
antiduh
2014-07-02 21:54:50 +00:00
parent 8a353227db
commit 3611034f82
5 changed files with 139 additions and 12 deletions

View File

@@ -9,12 +9,30 @@ using NSspi.Credentials;
namespace NSspi.Contexts namespace NSspi.Contexts
{ {
/// <summary>
/// Represents a client security context. Provides the means to establish a shared security context
/// with the server and to encrypt, decrypt, sign and verify messages to and from the server.
/// </summary>
/// <remarks>
/// A client and server establish a shared security context by exchanging authentication tokens. Once
/// the shared context is established, the client and server can pass messages to each other, encrypted,
/// signed, etc, using the established parameters of the shared context.
/// </remarks>
public class ClientContext : Context public class ClientContext : Context
{ {
private ContextAttrib requestedAttribs; private ContextAttrib requestedAttribs;
private ContextAttrib finalAttribs; private ContextAttrib finalAttribs;
private string serverPrinc; private string serverPrinc;
/// <summary>
/// Initializes a new instance of the ClientContext class. The context is not fully initialized and usable
/// until the authentication cycle has been completed.
/// </summary>
/// <param name="cred">The security credential to authenticate as.</param>
/// <param name="serverPrinc">The principle name of the server to connect to, or null for any.</param>
/// <param name="requestedAttribs">Requested attributes that describe the desired properties of the
/// context once it is established. If a context cannot be established that satisfies the indicated
/// properties, the context initialization is aborted.</param>
public ClientContext( ClientCredential cred, string serverPrinc, ContextAttrib requestedAttribs ) public ClientContext( ClientCredential cred, string serverPrinc, ContextAttrib requestedAttribs )
: base( cred ) : base( cred )
{ {
@@ -22,6 +40,28 @@ namespace NSspi.Contexts
this.requestedAttribs = requestedAttribs; this.requestedAttribs = requestedAttribs;
} }
/// <summary>
/// Performs and continues the authentication cycle.
/// </summary>
/// <remarks>
/// This method is performed iteratively to start, continue, and end the authentication cycle with the
/// server. Each stage works by acquiring a token from one side, presenting it to the other side
/// which in turn may generate a new token.
///
/// The cycle typically starts and ends with the client. On the first invocation on the client,
/// no server token exists, and null is provided in its place. The client returns its status, providing
/// its output token for the server. The server accepts the clients token as input and provides a
/// token as output to send back to the client. This cycle continues until the server and client
/// both indicate, typically, a SecurityStatus of 'OK'.
/// </remarks>
/// <param name="serverToken">The most recently received token from the server, or null if beginning
/// the authentication cycle.</param>
/// <param name="outToken">The clients next authentication token in the authentication cycle.</param>
/// <returns>A status message indicating the progression of the authentication cycle.
/// A status of 'OK' indicates that the cycle is complete, from the client's perspective. If the outToken
/// is not null, it must be sent to the server.
/// A status of 'Continue' indicates that the output token should be sent to the server and
/// a response should be anticipated.</returns>
public SecurityStatus Init( byte[] serverToken, out byte[] outToken ) public SecurityStatus Init( byte[] serverToken, out byte[] outToken )
{ {
TimeStamp rawExpiry = new TimeStamp(); TimeStamp rawExpiry = new TimeStamp();

View File

@@ -11,6 +11,9 @@ using NSspi.Contexts;
namespace NSspi.Contexts namespace NSspi.Contexts
{ {
/// <summary>
/// Declares native methods calls for security context-related win32 functions.
/// </summary>
internal static class ContextNativeMethods internal static class ContextNativeMethods
{ {
/* /*
@@ -173,7 +176,15 @@ namespace NSspi.Contexts
[DllImport( "Secur32.dll", EntryPoint = "RevertSecurityContext", CharSet = CharSet.Unicode )] [DllImport( "Secur32.dll", EntryPoint = "RevertSecurityContext", CharSet = CharSet.Unicode )]
internal static extern SecurityStatus RevertSecurityContext( ref RawSspiHandle contextHandle ); internal static extern SecurityStatus RevertSecurityContext( ref RawSspiHandle contextHandle );
/// <summary>
/// Safely invokes the native EncryptMessage function, making sure that handle ref counting is
/// performed in a proper CER.
/// </summary>
/// <param name="handle"></param>
/// <param name="qualityOfProtection"></param>
/// <param name="bufferAdapter"></param>
/// <param name="sequenceNumber"></param>
/// <returns></returns>
internal static SecurityStatus SafeEncryptMessage( internal static SecurityStatus SafeEncryptMessage(
SafeContextHandle handle, SafeContextHandle handle,
int qualityOfProtection, int qualityOfProtection,
@@ -216,6 +227,15 @@ namespace NSspi.Contexts
return status; return status;
} }
/// <summary>
/// Safely invokes the native DecryptMessage function, making sure that handle ref counting is
/// performed in a proper CER.
/// </summary>
/// <param name="handle"></param>
/// <param name="qualityOfProtection"></param>
/// <param name="bufferAdapter"></param>
/// <param name="sequenceNumber"></param>
/// <returns></returns>
internal static SecurityStatus SafeDecryptMessage( internal static SecurityStatus SafeDecryptMessage(
SafeContextHandle handle, SafeContextHandle handle,
int qualityOfProtection, int qualityOfProtection,
@@ -258,6 +278,15 @@ namespace NSspi.Contexts
return status; return status;
} }
/// <summary>
/// Safely invokes the native MakeSignature function, making sure that handle ref counting is
/// performed in a proper CER.
/// </summary>
/// <param name="handle"></param>
/// <param name="qualityOfProtection"></param>
/// <param name="adapter"></param>
/// <param name="sequenceNumber"></param>
/// <returns></returns>
internal static SecurityStatus SafeMakeSignature( internal static SecurityStatus SafeMakeSignature(
SafeContextHandle handle, SafeContextHandle handle,
int qualityOfProtection, int qualityOfProtection,
@@ -300,6 +329,15 @@ namespace NSspi.Contexts
return status; return status;
} }
/// <summary>
/// Safely invokes the native VerifySignature function, making sure that handle ref counting is
/// performed in a proper CER.
/// </summary>
/// <param name="handle"></param>
/// <param name="qualityOfProtection"></param>
/// <param name="adapter"></param>
/// <param name="sequenceNumber"></param>
/// <returns></returns>
internal static SecurityStatus SafeVerifySignature( internal static SecurityStatus SafeVerifySignature(
SafeContextHandle handle, SafeContextHandle handle,
int qualityOfProtection, int qualityOfProtection,

View File

@@ -6,21 +6,27 @@ using System.Threading.Tasks;
namespace NSspi.Contexts namespace NSspi.Contexts
{ {
/// <summary>
/// Represents impersonation performed on a server on behalf of a client.
/// </summary>
/// <remarks>
/// The handle controls the lifetime of impersonation, and will revert the impersonation
/// if it is disposed, or if it is finalized ie by being leaked and garbage collected.
///
/// If the handle is accidentally leaked while operations are performed on behalf of the user,
/// impersonation may be reverted at any arbitrary time, perhaps during those operations.
/// This may lead to operations being performed in the security context of the server,
/// potentially leading to security vulnerabilities.
/// </remarks>
public class ImpersonationHandle : IDisposable public class ImpersonationHandle : IDisposable
{ {
// Notes:
// Impersonate:
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa375497(v=vs.85).aspx
//
// Revert:
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa379446(v=vs.85).aspx
//
// QuerySecurityPkgInfo (to learn if it supports impersonation):
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa379359(v=vs.85).aspx
private bool disposed; private bool disposed;
private ServerContext server; private ServerContext server;
/// <summary>
/// Initializes a new instance of the ImpersonationHandle. Does not perform impersonation.
/// </summary>
/// <param name="server">The server context that is performing impersonation.</param>
internal ImpersonationHandle(ServerContext server) internal ImpersonationHandle(ServerContext server)
{ {
this.server = server; this.server = server;
@@ -32,6 +38,9 @@ namespace NSspi.Contexts
Dispose( false ); Dispose( false );
} }
/// <summary>
/// Reverts the impersonation.
/// </summary>
public void Dispose() public void Dispose()
{ {
Dispose( true ); Dispose( true );

View File

@@ -7,7 +7,9 @@ using System.Threading.Tasks;
namespace NSspi.Contexts namespace NSspi.Contexts
{ {
/// <summary>
/// Captures an unmanaged security context handle.
/// </summary>
public class SafeContextHandle : SafeSspiHandle public class SafeContextHandle : SafeSspiHandle
{ {
public SafeContextHandle() public SafeContextHandle()

View File

@@ -34,6 +34,28 @@ namespace NSspi.Contexts
/// </remarks> /// </remarks>
public bool SupportsImpersonate { get; private set; } public bool SupportsImpersonate { get; private set; }
/// <summary>
/// Performs and continues the authentication cycle.
/// </summary>
/// <remarks>
/// This method is performed iteratively to continue and end the authentication cycle with the
/// client. Each stage works by acquiring a token from one side, presenting it to the other side
/// which in turn may generate a new token.
///
/// The cycle typically starts and ends with the client. On the first invocation on the client,
/// no server token exists, and null is provided in its place. The client returns its status, providing
/// its output token for the server. The server accepts the clients token as input and provides a
/// token as output to send back to the client. This cycle continues until the server and client
/// both indicate, typically, a SecurityStatus of 'OK'.
/// </remarks>
/// <param name="clientToken">The most recently received token from the client.</param>
/// <param name="nextToken">The servers next authentication token in the cycle, that must
/// be sent to the client.</param>
/// <returns>A status message indicating the progression of the authentication cycle.
/// A status of 'OK' indicates that the cycle is complete, from the servers's perspective. If the nextToken
/// is not null, it must be sent to the client.
/// A status of 'Continue' indicates that the output token should be sent to the client and
/// a response should be anticipated.</returns>
public SecurityStatus AcceptToken( byte[] clientToken, out byte[] nextToken ) public SecurityStatus AcceptToken( byte[] clientToken, out byte[] nextToken )
{ {
SecureBuffer clientBuffer; SecureBuffer clientBuffer;
@@ -125,6 +147,19 @@ namespace NSspi.Contexts
return status; return status;
} }
/// <summary>
/// Changes the current thread's security context to impersonate the user of the client.
/// </summary>
/// <remarks>
/// Requires that the security package provided with the server's credentials, as well as the
/// client's credentials, support impersonation.
///
/// Currently, only one thread may initiate impersonation per security context. Impersonation may
/// follow threads created by the initial impersonation thread, however.
/// </remarks>
/// <returns>A handle to capture the lifetime of the impersonation. Dispose the handle to revert
/// impersonation. If the handle is leaked, the impersonation will automatically revert at a
/// non-deterministic time when the handle is finalized by the Garbage Collector.</returns>
public ImpersonationHandle ImpersonateClient() public ImpersonationHandle ImpersonateClient()
{ {
ImpersonationHandle handle; ImpersonationHandle handle;
@@ -192,6 +227,9 @@ namespace NSspi.Contexts
return handle; return handle;
} }
/// <summary>
/// Called by the ImpersonationHandle when it is released, either by disposale or finalization.
/// </summary>
internal void RevertImpersonate() internal void RevertImpersonate()
{ {
bool gotRef = false; bool gotRef = false;