/// <summary> /// Constructs an instance of the SspiClientSecurityContext class. /// </summary> /// <param name="keyProvider_SspiClient">Parent factory to get settings from.</param> public SspiClientSecurityContext(KeyProvider_SspiClient keyProvider_SspiClient) { // write settings this.KeyProvider_SspiClient = keyProvider_SspiClient; // // WAS: // // get credentials handle // SspiApi.AcquireCredentialsHandle(keyProvider_SspiClient.AuthIdentity, // keyProvider_SspiClient.PackageName, SspiApi.SECPKG_CRED_OUTBOUND, // this._credHandle, ref this._ptsExpiry); if (this.KeyProvider_SspiClient.DelegatedContext == null) { // get credentials handle SspiApi.AcquireCredentialsHandle(keyProvider_SspiClient.AuthIdentity, keyProvider_SspiClient.PackageName, SspiApi.SECPKG_CRED_BOTH, this._credHandle, ref this._ptsExpiry); } else { SspiApi.AcquireCredentialsHandle(keyProvider_SspiClient.AuthIdentity, keyProvider_SspiClient.PackageName, SspiApi.SECPKG_CRED_BOTH, this._credHandle, ref this._ptsExpiry); } }
/// <summary> /// Constructs an instance of the SspiServerSecurityContext class. /// </summary> /// <param name="keyProvider_SspiServer">Parent KeyProvider_SspiServer factory.</param> public SspiServerSecurityContext(KeyProvider_SspiServer keyProvider_SspiServer) { this.KeyProvider_SspiServer = keyProvider_SspiServer; // get credentials handle SspiApi.AcquireCredentialsHandle(null, this.KeyProvider_SspiServer.PackageName, SspiApi.SECPKG_CRED_INBOUND, this._credHandle, ref this._ptsExpiry); }
/// <summary> /// Builds up a security context between the client application and a remote peer. /// Should be called until continueProcessing is false. /// </summary> /// <param name="receivedData">Data received from the remote host.</param> /// <param name="outputStream">Stream to write the data being sent into.</param> /// <returns>True if security context has been succesfully built up.</returns> public bool BuildUpSecurityContext(Stream receivedData, Stream outputStream) { bool result = SspiApi.InitializeSecurityContext(this._credHandle, receivedData == null ? null : this._phContext, this._phContext, this.KeyProvider_SspiClient.ServerName, this.KeyProvider_SspiClient.RequiredFeatures, ref this._ptsExpiry, receivedData, outputStream); this.ContinueProcessing = !result; return(result); }
/// <summary> /// Builds up a security context between the client application and a remote peer. /// Should be called until continueProcessing is false. /// </summary> /// <param name="receivedData">Data received from the remote host.</param> /// <param name="outputStream">Stream to write the data being sent into.</param> /// <returns>True if security context has been succesfully built up.</returns> public bool BuildUpSecurityContext(Stream receivedData, Stream outputStream) { bool result = SspiApi.AcceptSecurityContext(this._credHandle, this._phContext, this.KeyProvider_SspiServer.RequiredFeatures, ref this._ptsExpiry, receivedData, outputStream, firstCall); firstCall = false; this.ContinueProcessing = !result; return(result); }
/// <summary> /// Releases all acquired SSPI resources. /// </summary> public void Dispose() { if (this._disposed) { return; } this._disposed = true; #if TRIAL #else SspiApi.DeleteSecurityContext(this._phContext); SspiApi.FreeCredentialsHandle(this._credHandle); #endif }
/// <summary> /// Encrypts the stream under current security conditions. /// </summary> /// <param name="messageStream">Data to be encrypted.</param> /// <param name="outputStream">Stream to write encrypted content to.</param> /// <param name="sspiFeatureFlags">Requested features.</param> public void EncryptMessage(Stream messageStream, GenuineChunkedStream outputStream, SspiFeatureFlags sspiFeatureFlags) { // get package sizes lock (_secPkgContext_SizesLock) { if (!_secPkgContext_SizesInitialized) { SspiApi.QueryContextSizes(this._phContext, ref this._secPkgContext_Sizes); _secPkgContext_SizesInitialized = true; } } byte[] chunk = null; int position = 0; BinaryWriter outputWriter = new BinaryWriter(outputStream); if ((sspiFeatureFlags & SspiFeatureFlags.Encryption) != 0) { // it'll write signature automatically as well as encrypt content SspiApi.EncryptMessage(this._phContext, messageStream, outputWriter, ref this._secPkgContext_Sizes); } else if ((sspiFeatureFlags & SspiFeatureFlags.Signing) != 0) { // remember position to write signature size later outputStream.WriteInt32AndRememberItsLocation(0, out chunk, out position); long currentLength = outputStream.Length; // anyway will have to read this into buffer byte[] contentBuffer = new byte[(int)messageStream.Length]; GenuineUtility.ReadDataFromStream(messageStream, contentBuffer, 0, contentBuffer.Length); // write signature SspiApi.MakeSignature(this._phContext, contentBuffer, outputWriter, ref this._secPkgContext_Sizes); // update signature size MessageCoder.WriteInt32(chunk, position, (int)(outputStream.Length - currentLength)); // write the content outputWriter.Write((int)contentBuffer.Length); outputWriter.Write(contentBuffer, 0, contentBuffer.Length); } else { // just copy the source content //outputWriter.Write( (int) messageStream.Length ); GenuineUtility.CopyStreamToStream(messageStream, outputStream); } }
/// <summary> /// Decrypts the data. /// </summary> /// <param name="sourceStream">Stream containing encrypted data.</param> /// <param name="sspiFeatureFlags">Requested SSPI features.</param> /// <returns>Stream containing decrypted data.</returns> public Stream DecryptMessage(Stream sourceStream, SspiFeatureFlags sspiFeatureFlags) { // get package sizes lock (_secPkgContext_SizesLock) { if (!_secPkgContext_SizesInitialized) { SspiApi.QueryContextSizes(this._phContext, ref this._secPkgContext_Sizes); _secPkgContext_SizesInitialized = true; } } BinaryReader messageReader = new BinaryReader(sourceStream); if ((sspiFeatureFlags & SspiFeatureFlags.Encryption) != 0) { // decrypt it return(SspiApi.DecryptMessage(this._phContext, messageReader)); } else if ((sspiFeatureFlags & SspiFeatureFlags.Signing) != 0) { // read signature int signatureSize = messageReader.ReadInt32(); byte[] signature = new byte[signatureSize]; GenuineUtility.ReadDataFromStream(sourceStream, signature, 0, signatureSize); // read content int contentSize = messageReader.ReadInt32(); byte[] content = new byte[contentSize]; GenuineUtility.ReadDataFromStream(sourceStream, content, 0, contentSize); // verify signature SspiApi.VerifySignature(this._phContext, content, signature); // return verified content return(new MemoryStream(content, 0, content.Length, false, true)); } return(sourceStream); }
/// <summary> /// Sets up correct security context and invokes a target. /// This method may not throw any exceptions. /// </summary> /// <param name="message">The message to be performed.</param> /// <param name="connectionLevel">Indicates whether Security Session is used on the connection level.</param> public override void Invoke(Message message, bool connectionLevel) { bool impersonateContext = (this.KeyProvider_SspiServer.RequiredFeatures & SspiFeatureFlags.Impersonation) != 0 || (this.KeyProvider_SspiServer.RequiredFeatures & SspiFeatureFlags.Delegation) != 0; try { if (impersonateContext) { SspiApi.ImpersonateSecurityContext(this.SspiSecurityContext._phContext); } base.Invoke(message, connectionLevel); } finally { if (impersonateContext) { SspiApi.RevertSecurityContext(this.SspiSecurityContext._phContext); } } }
/// <summary> /// Initiates or continues establishing of the Security Session. /// Implementation notes: receiving of exceptions no more breaks up the connection like /// it was in the previous versions. /// </summary> /// <param name="input">A null reference or an incoming stream.</param> /// <param name="connectionLevel">Indicates whether the Security Session operates on connection level.</param> /// <returns>A stream containing data for sending to the remote host or a null reference if Security Session is established.</returns> public override GenuineChunkedStream EstablishSession(Stream input, bool connectionLevel) { bool passException = false; // a dance is over if (this.IsEstablished) { return(null); } GenuineChunkedStream outputStream = null; var binaryFormatter = new BinaryFormatter().Safe(); // skip the status flag if (connectionLevel) { if (input != null) { input.ReadByte(); } outputStream = new GenuineChunkedStream(false); } else { outputStream = this.CreateOutputStream(); } // write session is being established flag BinaryWriter binaryWriter = new BinaryWriter(outputStream); binaryWriter.Write((byte)0); try { lock (this) { if (input == Stream.Null) { if (this.KeyProvider_SspiClient.DelegatedContext != null) { try { SspiApi.ImpersonateSecurityContext(this.KeyProvider_SspiClient.DelegatedContext.SspiSecurityContext._phContext); // start new session this.SspiSecurityContext = new SspiClientSecurityContext(this.KeyProvider_SspiClient); binaryWriter.Write((byte)SspiPacketStatusFlags.InitializeFromScratch); this.SspiSecurityContext.BuildUpSecurityContext(null, outputStream); return(outputStream); } finally { SspiApi.RevertSecurityContext(this.KeyProvider_SspiClient.DelegatedContext.SspiSecurityContext._phContext); } } // start new session this.SspiSecurityContext = new SspiClientSecurityContext(this.KeyProvider_SspiClient); binaryWriter.Write((byte)SspiPacketStatusFlags.InitializeFromScratch); this.SspiSecurityContext.BuildUpSecurityContext(null, outputStream); return(outputStream); } SspiPacketStatusFlags sspiPacketStatusFlags = (SspiPacketStatusFlags)input.ReadByte(); switch (sspiPacketStatusFlags) { case SspiPacketStatusFlags.ContinueAuthentication: // continue building a security context GenuineChunkedStream sspiData = new GenuineChunkedStream(false); this.SspiSecurityContext.BuildUpSecurityContext(input, sspiData); if (sspiData.Length == 0) { // SSPI session has been built up outputStream.WriteByte((byte)SspiPacketStatusFlags.SessionEstablished); this.SessionEstablished(); } else { outputStream.WriteByte((byte)SspiPacketStatusFlags.ContinueAuthentication); outputStream.WriteStream(sspiData); } return(outputStream); case SspiPacketStatusFlags.ExceptionThrown: Exception receivedException = GenuineUtility.ReadException(input); #if DEBUG // this.Remote.ITransportContext.IEventLogger.Log(LogMessageCategory.Security, receivedException, "SecuritySession_SspiServer.EstablishSession", // null, "SSPI initialization ends up with an exception at the remote host. Remote host: {0}.", // this.Remote.ToString()); #endif if (this.Remote != null) { this.Remote.ITransportContext.IGenuineEventProvider.Fire(new GenuineEventArgs( GenuineEventType.SecuritySessionFailed, receivedException, this.Remote, this)); } this.DispatchException(receivedException); passException = true; throw receivedException; case SspiPacketStatusFlags.ForceInitialization: return(this.EstablishSession(Stream.Null, connectionLevel)); case SspiPacketStatusFlags.InitializeFromScratch: throw GenuineExceptions.Get_Processing_LogicError( string.Format("The remote host must have the Security Session of the type SecuritySession_SspiServer registered with the name {0}. SecuritySession_SspiServer never sends SspiPacketMark.InitializeFromScratch packet marker.", this.Name)); case SspiPacketStatusFlags.SessionEstablished: this.SessionEstablished(); break; } } } catch (Exception opEx) { #if DEBUG // this.Remote.ITransportContext.IEventLogger.Log(LogMessageCategory.Security, opEx, "SecuritySession_SspiServer.EstablishSession", // null, "Exception was thrown while establishing security context."); #endif if (this.Remote != null) { this.Remote.ITransportContext.IGenuineEventProvider.Fire(new GenuineEventArgs( GenuineEventType.SecuritySessionFailed, opEx, this.Remote, this)); } this.DispatchException(opEx); if (passException) { throw; } binaryWriter.Write((byte)SspiPacketStatusFlags.ExceptionThrown); binaryFormatter.Serialize(outputStream, opEx); return(outputStream); } return(null); }