private void Init(CCredentialUse use) { string packageName; CTimeStamp rawExpiry = new CTimeStamp(); CSecurityStatus status = CSecurityStatus.InternalError; // -- Package -- // Copy off for the call, since this.SecurityPackage is a property. packageName = this.SecurityPackage; this.Handle = new CSafeCredentialHandle(); // The finally clause is the actual constrained region. The VM pre-allocates any stack space, // performs any allocations it needs to prepare methods for execution, and postpones any // instances of the 'uncatchable' exceptions (ThreadAbort, StackOverflow, OutOfMemory). RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { status = CCredentialNativeMethods.AcquireCredentialsHandle( null, packageName, use, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ref this.Handle.rawHandle, ref rawExpiry ); } if (status != CSecurityStatus.OK) { throw new CSSPIException("Failed to call AcquireCredentialHandle", status); } this.Expiry = rawExpiry.ToDateTime(); }
/// <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 CSecurityStatus AcceptToken(byte[] clientToken, out byte[] nextToken) { CSecureBuffer clientBuffer; CSecureBuffer outBuffer; CSecurityStatus status; CTimeStamp rawExpiry = new CTimeStamp(); CSecureBufferAdapter clientAdapter; CSecureBufferAdapter outAdapter; if (this.Disposed) { throw new ObjectDisposedException("ServerContext"); } else if (this.Initialized) { throw new InvalidOperationException( "Attempted to continue initialization of a ServerContext after initialization had completed." ); } clientBuffer = new CSecureBuffer(clientToken, CBufferType.Token); outBuffer = new CSecureBuffer( new byte[this.Credential.PackageInfo.MaxTokenLength], CBufferType.Token ); using (clientAdapter = new CSecureBufferAdapter(clientBuffer)) { using (outAdapter = new CSecureBufferAdapter(outBuffer)) { if (this.ContextHandle.IsInvalid) { status = CContextNativeMethods.AcceptSecurityContext_1( ref this.Credential.Handle.rawHandle, IntPtr.Zero, clientAdapter.Handle, requestedAttribs, CSecureBufferDataRep.Network, ref this.ContextHandle.rawHandle, outAdapter.Handle, ref this.finalAttribs, ref rawExpiry ); } else { status = CContextNativeMethods.AcceptSecurityContext_2( ref this.Credential.Handle.rawHandle, ref this.ContextHandle.rawHandle, clientAdapter.Handle, requestedAttribs, CSecureBufferDataRep.Network, ref this.ContextHandle.rawHandle, outAdapter.Handle, ref this.finalAttribs, ref rawExpiry ); } } } if (status == CSecurityStatus.OK) { nextToken = null; base.Initialize(rawExpiry.ToDateTime()); if (outBuffer.Length != 0) { nextToken = new byte[outBuffer.Length]; Array.Copy(outBuffer.Buffer, nextToken, nextToken.Length); } else { nextToken = null; } } else if (status == CSecurityStatus.ContinueNeeded) { nextToken = new byte[outBuffer.Length]; Array.Copy(outBuffer.Buffer, nextToken, nextToken.Length); } else { throw new CSSPIException("Failed to call AcceptSecurityContext", status); } return(status); }
/// <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 CSecurityStatus Init(byte[] serverToken, out byte[] outToken) { CTimeStamp rawExpiry = new CTimeStamp(); CSecurityStatus status; CSecureBuffer outTokenBuffer; CSecureBufferAdapter outAdapter; CSecureBuffer serverBuffer; CSecureBufferAdapter serverAdapter; if (this.Disposed) { throw new ObjectDisposedException("ClientContext"); } else if ((serverToken != null) && (this.ContextHandle.IsInvalid)) { throw new InvalidOperationException("Out-of-order usage detected - have a server token, but no previous client token had been created."); } else if ((serverToken == null) && (this.ContextHandle.IsInvalid == false)) { throw new InvalidOperationException("Must provide the server's response when continuing the init process."); } // The security package tells us how big its biggest token will be. We'll allocate a buffer // that size, and it'll tell us how much it used. outTokenBuffer = new CSecureBuffer( new byte[this.Credential.PackageInfo.MaxTokenLength], CBufferType.Token ); serverBuffer = null; if (serverToken != null) { serverBuffer = new CSecureBuffer(serverToken, CBufferType.Token); } // Some notes on handles and invoking InitializeSecurityContext // - The first time around, the phContext parameter (the 'old' handle) is a null pointer to what // would be an RawSspiHandle, to indicate this is the first time it's being called. // The phNewContext is a pointer (reference) to an RawSspiHandle struct of where to write the // new handle's values. // - The next time you invoke ISC, it takes a pointer to the handle it gave you last time in phContext, // and takes a pointer to where it should write the new handle's values in phNewContext. // - After the first time, you can provide the same handle to both parameters. From MSDN: // "On the second call, phNewContext can be the same as the handle specified in the phContext // parameter." // It will overwrite the handle you gave it with the new handle value. // - All handle structures themselves are actually *two* pointer variables, eg, 64 bits on 32-bit // Windows, 128 bits on 64-bit Windows. // - So in the end, on a 64-bit machine, we're passing a 64-bit value (the pointer to the struct) that // points to 128 bits of memory (the struct itself) for where to write the handle numbers. using (outAdapter = new CSecureBufferAdapter(outTokenBuffer)) { if (this.ContextHandle.IsInvalid) { status = CContextNativeMethods.InitializeSecurityContext_1( ref this.Credential.Handle.rawHandle, IntPtr.Zero, this.serverPrinc, this.requestedAttribs, 0, CSecureBufferDataRep.Network, IntPtr.Zero, 0, ref this.ContextHandle.rawHandle, outAdapter.Handle, ref this.finalAttribs, ref rawExpiry ); } else { using (serverAdapter = new CSecureBufferAdapter(serverBuffer)) { status = CContextNativeMethods.InitializeSecurityContext_2( ref this.Credential.Handle.rawHandle, ref this.ContextHandle.rawHandle, this.serverPrinc, this.requestedAttribs, 0, CSecureBufferDataRep.Network, serverAdapter.Handle, 0, ref this.ContextHandle.rawHandle, outAdapter.Handle, ref this.finalAttribs, ref rawExpiry ); } } } if (status.IsError() == false) { if (status == CSecurityStatus.OK) { base.Initialize(rawExpiry.ToDateTime()); } outToken = null; if (outTokenBuffer.Length != 0) { outToken = new byte[outTokenBuffer.Length]; Array.Copy(outTokenBuffer.Buffer, outToken, outToken.Length); } } else { throw new CSSPIException("Failed to invoke InitializeSecurityContext for a client", status); } return(status); }