public WstRequestSecurityToken ReadRequest (Message msg)
		{
			using (WSTrustRequestSecurityTokenReader reader =
				new WSTrustRequestSecurityTokenReader (msg.GetReaderAtBodyContents (), serializer)) {
				reader.Read ();
				return reader.Value;
			}
		}
		Message ProcessClientHello (Message request)
		{
			// FIXME: use correct buffer size
			MessageBuffer buffer = request.CreateBufferedCopy (0x10000);
			WSTrustRequestSecurityTokenReader reader =
				new WSTrustRequestSecurityTokenReader (buffer.CreateMessage ().GetReaderAtBodyContents (), SecurityTokenSerializer);
			reader.Read ();

			if (sessions.ContainsKey (reader.Value.Context))
				throw new SecurityNegotiationException (String.Format ("The context '{0}' already exists in this SSL negotiation manager", reader.Value.Context));

			TlsServerSession tls = new TlsServerSession (owner.Manager.ServiceCredentials.ServiceCertificate.Certificate, owner.IsMutual);
			TlsServerSessionInfo tlsInfo = new TlsServerSessionInfo (
				reader.Value.Context, tls);

			AppendNegotiationMessageXml (buffer.CreateMessage ().GetReaderAtBodyContents (), tlsInfo);

			tls.ProcessClientHello (reader.Value.BinaryExchange.Value);
			WstRequestSecurityTokenResponse rstr =
				new WstRequestSecurityTokenResponse (SecurityTokenSerializer);
			rstr.Context = reader.Value.Context;
			rstr.BinaryExchange = new WstBinaryExchange (Constants.WstBinaryExchangeValueTls);
			rstr.BinaryExchange.Value = tls.ProcessServerHello ();

			Message reply = Message.CreateMessage (request.Version, Constants.WstIssueReplyAction, rstr);
			reply.Headers.RelatesTo = request.Headers.MessageId;

			// FIXME: use correct buffer size
			buffer = reply.CreateBufferedCopy (0x10000);
			AppendNegotiationMessageXml (buffer.CreateMessage ().GetReaderAtBodyContents (), tlsInfo);

			sessions [reader.Value.Context] = tlsInfo;

			return buffer.CreateMessage ();
		}
		// FIXME: use timeout
		Message ProcessMessageType1 (Message request, TimeSpan timeout)
		{
			// FIXME: use correct buffer size
			MessageBuffer buffer = request.CreateBufferedCopy (0x10000);
			WSTrustRequestSecurityTokenReader reader =
				new WSTrustRequestSecurityTokenReader (buffer.CreateMessage ().GetReaderAtBodyContents (), SecurityTokenSerializer);
			reader.Read ();

			if (sessions.ContainsKey (reader.Value.Context))
				throw new SecurityNegotiationException (String.Format ("The context '{0}' already exists in this SSL negotiation manager", reader.Value.Context));

			/* Console.WriteLine (buffer.CreateMessage ()); */

			SspiServerSession sspi = new SspiServerSession ();
//			AppendNegotiationMessageXml (buffer.CreateMessage ().GetReaderAtBodyContents (), tlsInfo);

			// FIXME: when an explicit endpoint identity is
			// specified in the target EndpointAddress at client,
			// it sends some other kind of binary octets that
			// include NTLM octet, instead of raw NTLM octet itself.

			byte [] raw = reader.Value.BinaryExchange.Value;

			bool gss = "NTLMSSP" != Encoding.ASCII.GetString (raw, 0, 7);

			if (gss)
				sspi.ProcessSpnegoInitialContextTokenRequest (raw);
			else
				sspi.ProcessMessageType1 (raw);

			WstRequestSecurityTokenResponse rstr =
				new WstRequestSecurityTokenResponse (SecurityTokenSerializer);
			rstr.Context = reader.Value.Context;
			rstr.BinaryExchange = new WstBinaryExchange (Constants.WstBinaryExchangeValueGss);

			if (gss)
				rstr.BinaryExchange.Value = sspi.ProcessSpnegoInitialContextTokenResponse ();
			else
				rstr.BinaryExchange.Value = sspi.ProcessMessageType2 ();

			Message reply = Message.CreateMessage (request.Version, Constants.WstIssueReplyAction, rstr);
			reply.Headers.RelatesTo = request.Headers.MessageId;

			// FIXME: use correct buffer size
			buffer = reply.CreateBufferedCopy (0x10000);
//			AppendNegotiationMessageXml (buffer.CreateMessage ().GetReaderAtBodyContents (), tlsInfo);

			sessions [reader.Value.Context] = sspi;

			return buffer.CreateMessage ();
		}
		// FIXME: use timeout
		Message ProcessClientHello (Message request, TimeSpan timeout)
		{
			// FIXME: use correct buffer size
			MessageBuffer buffer = request.CreateBufferedCopy (0x10000);
			WSTrustRequestSecurityTokenReader reader =
				new WSTrustRequestSecurityTokenReader (buffer.CreateMessage ().GetReaderAtBodyContents (), SecurityTokenSerializer);
			reader.Read ();

			if (sessions.ContainsKey (reader.Value.Context))
				throw new SecurityNegotiationException (String.Format ("The context '{0}' already exists in this SSL negotiation manager", reader.Value.Context));

			// FIXME: it seems .NET retrieves X509 Certificate through CreateSecurityTokenProvider(somex509requirement).GetToken().SecurityKeys[0]
			// (should result in X509AsymmetricSecurityKey) and continues tlsstart.
			// That's not very required feature so I ignore it.
			TlsServerSession tls = new TlsServerSession (owner.Manager.ServiceCredentials.ServiceCertificate.Certificate, owner.IsMutual);
			TlsServerSessionInfo tlsInfo = new TlsServerSessionInfo (
				reader.Value.Context, tls);

			AppendNegotiationMessageXml (buffer.CreateMessage ().GetReaderAtBodyContents (), tlsInfo);

			tls.ProcessClientHello (reader.Value.BinaryExchange.Value);
			WstRequestSecurityTokenResponse rstr =
				new WstRequestSecurityTokenResponse (SecurityTokenSerializer);
			rstr.Context = reader.Value.Context;
			rstr.BinaryExchange = new WstBinaryExchange (Constants.WstBinaryExchangeValueTls);
			rstr.BinaryExchange.Value = tls.ProcessServerHello ();

			Message reply = Message.CreateMessage (request.Version, Constants.WstIssueReplyAction, rstr);
			reply.Headers.RelatesTo = request.Headers.MessageId;

			// FIXME: use correct buffer size
			buffer = reply.CreateBufferedCopy (0x10000);
			AppendNegotiationMessageXml (buffer.CreateMessage ().GetReaderAtBodyContents (), tlsInfo);

			sessions [reader.Value.Context] = tlsInfo;

			return buffer.CreateMessage ();
		}