示例#1
0
        public SecurityToken GetToken(TimeSpan timeout)
        {
            TlsnegoClientSessionContext tlsctx =
                new TlsnegoClientSessionContext();
            TlsClientSession        tls = new TlsClientSession(IssuerAddress.Uri.ToString(), client_certificate, owner.Manager.ClientCredentials.ServiceCertificate.Authentication);
            WstRequestSecurityToken rst =
                new WstRequestSecurityToken();
            string contextId = rst.Context;

            // send ClientHello
            rst.BinaryExchange       = new WstBinaryExchange(Constants.WstBinaryExchangeValueTls);
            rst.BinaryExchange.Value = tls.ProcessClientHello();

            Message request = Message.CreateMessage(IssuerBinding.MessageVersion, Constants.WstIssueAction, rst);

            request.Headers.MessageId = new UniqueId();
            request.Headers.ReplyTo   = new EndpointAddress(Constants.WsaAnonymousUri);
            request.Headers.To        = TargetAddress.Uri;
            MessageBuffer buffer = request.CreateBufferedCopy(0x10000);

            tlsctx.StoreMessage(buffer.CreateMessage().GetReaderAtBodyContents());
            Message response = proxy.Issue(buffer.CreateMessage());

            // FIXME: use correct limitation
            buffer = response.CreateBufferedCopy(0x10000);
            tlsctx.StoreMessage(buffer.CreateMessage().GetReaderAtBodyContents());

            // receive ServerHello
            WSTrustRequestSecurityTokenResponseReader reader =
                new WSTrustRequestSecurityTokenResponseReader(Constants.WstTlsnegoProofTokenType, buffer.CreateMessage().GetReaderAtBodyContents(), SecurityTokenSerializer, null);

            reader.Read();
            if (reader.Value.RequestedSecurityToken != null)
            {
                return(reader.Value.RequestedSecurityToken);
            }

            tls.ProcessServerHello(reader.Value.BinaryExchange.Value);

            // send ClientKeyExchange
            WstRequestSecurityTokenResponse rstr =
                new WstRequestSecurityTokenResponse(SecurityTokenSerializer);

            rstr.Context              = reader.Value.Context;
            rstr.BinaryExchange       = new WstBinaryExchange(Constants.WstBinaryExchangeValueTls);
            rstr.BinaryExchange.Value = tls.ProcessClientKeyExchange();

            request = Message.CreateMessage(IssuerBinding.MessageVersion, Constants.WstIssueReplyAction, rstr);
            request.Headers.ReplyTo = new EndpointAddress(Constants.WsaAnonymousUri);
            request.Headers.To      = TargetAddress.Uri;

            buffer = request.CreateBufferedCopy(0x10000);
            tlsctx.StoreMessage(buffer.CreateMessage().GetReaderAtBodyContents());
//Console.WriteLine (System.Text.Encoding.UTF8.GetString (tlsctx.GetC14NResults ()));

            // FIXME: regeneration of this instance is somehow required, but should not be.
            proxy = new WSTrustSecurityTokenServiceProxy(
                IssuerBinding, IssuerAddress);
            response = proxy.IssueReply(buffer.CreateMessage());
            // FIXME: use correct limitation
            buffer = response.CreateBufferedCopy(0x10000);

            WstRequestSecurityTokenResponseCollection coll =
                new WstRequestSecurityTokenResponseCollection();

            coll.Read(Constants.WstTlsnegoProofTokenType, buffer.CreateMessage().GetReaderAtBodyContents(), SecurityTokenSerializer, null);
            if (coll.Responses.Count != 2)
            {
                throw new SecurityNegotiationException(String.Format("Expected response is RequestSecurityTokenResponseCollection which contains two RequestSecurityTokenResponse items, but it actually contains {0} items", coll.Responses.Count));
            }

            WstRequestSecurityTokenResponse r = coll.Responses [0];

            tls.ProcessServerFinished(r.BinaryExchange.Value);
            SecurityContextSecurityToken sctSrc =
                r.RequestedSecurityToken;

#if false // FIXME: should this final RSTR included in RSTRC considered too?
            XmlDocument doc = new XmlDocument();
            doc.PreserveWhitespace = true;
            using (XmlDictionaryWriter dw = XmlDictionaryWriter.CreateDictionaryWriter(doc.CreateNavigator().AppendChild()))
            {
                if (r == null)
                {
                    throw new Exception("r");
                }
                if (dw == null)
                {
                    throw new Exception("dw");
                }
                r.WriteBodyContents(dw);
            }
            tlsctx.StoreMessage(XmlDictionaryReader.CreateDictionaryReader(new XmlNodeReader(doc)));
#endif

            // the RequestedProofToken is represented as 32 bytes
            // of TLS ApplicationData.
            // - According to WSE2 doc, it is *the* key, but not
            //   sure it also applies to WCF.
            // - WSS4J also seems to store the encryped shared key.
            // - (Important) It seems that without tls decryption,
            //   .NET fails to recover the key.
            byte [] proof = tls.ProcessApplicationData(
                (byte [])r.RequestedProofToken);
            byte [] key = proof;

            // Authenticate token.

            byte [] actual = coll.Responses [1].Authenticator;
            if (actual == null)
            {
                throw new SecurityNegotiationException("Token authenticator is expected in the RequestSecurityTokenResponse but not found.");
            }

            if (coll.Responses [0].Context != contextId)
            {
                throw new SecurityNegotiationException("The context Id does not match with that of the corresponding token authenticator.");
            }

            // H = sha1(exc14n(RST..RSTRs))
            byte [] hash     = SHA1.Create().ComputeHash(tlsctx.GetC14NResults());
            byte [] referent = tls.CreateHash(key, hash, "AUTH-HASH");
            Console.WriteLine(System.Text.Encoding.ASCII.GetString(tlsctx.GetC14NResults()));
            Console.Write("Hash: ");
            foreach (byte b in hash)
            {
                Console.Write("{0:X02} ", b);
            }
            Console.WriteLine();
            Console.Write("Referent: ");
            foreach (byte b in referent)
            {
                Console.Write("{0:X02} ", b);
            }
            Console.WriteLine();
            Console.Write("Actual: ");
            foreach (byte b in actual)
            {
                Console.Write("{0:X02} ", b);
            }
            Console.WriteLine();
            Console.Write("Proof: ");
            foreach (byte b in proof)
            {
                Console.Write("{0:X02} ", b);
            }
            Console.WriteLine();
            bool mismatch = referent.Length != actual.Length;
            if (!mismatch)
            {
                for (int i = 0; i < referent.Length; i++)
                {
                    if (referent [i] != actual [i])
                    {
                        mismatch = true;
                    }
                }
            }

            if (mismatch)
            {
                throw new SecurityNegotiationException("The CombinedHash does not match the expected value.");
            }

            return(sctSrc);
        }
示例#2
0
		public SecurityToken GetToken (TimeSpan timeout)
		{
			TlsnegoClientSessionContext tlsctx =
				new TlsnegoClientSessionContext ();
			TlsClientSession tls = new TlsClientSession (IssuerAddress.Uri.ToString (), client_certificate, owner.Manager.ClientCredentials.ServiceCertificate.Authentication);
			WstRequestSecurityToken rst =
				new WstRequestSecurityToken ();
			string contextId = rst.Context;

			// send ClientHello
			rst.BinaryExchange = new WstBinaryExchange (Constants.WstBinaryExchangeValueTls);
			rst.BinaryExchange.Value = tls.ProcessClientHello ();

			Message request = Message.CreateMessage (IssuerBinding.MessageVersion, Constants.WstIssueAction, rst);
			request.Headers.MessageId = new UniqueId ();
			request.Headers.ReplyTo = new EndpointAddress (Constants.WsaAnonymousUri);
			request.Headers.To = TargetAddress.Uri;
			MessageBuffer buffer = request.CreateBufferedCopy (0x10000);
			tlsctx.StoreMessage (buffer.CreateMessage ().GetReaderAtBodyContents ());
			Message response = proxy.Issue (buffer.CreateMessage ());

			// FIXME: use correct limitation
			buffer = response.CreateBufferedCopy (0x10000);
			tlsctx.StoreMessage (buffer.CreateMessage ().GetReaderAtBodyContents ());

			// receive ServerHello
			WSTrustRequestSecurityTokenResponseReader reader =
				new WSTrustRequestSecurityTokenResponseReader (Constants.WstTlsnegoProofTokenType, buffer.CreateMessage ().GetReaderAtBodyContents (), SecurityTokenSerializer, null);
			reader.Read ();
			if (reader.Value.RequestedSecurityToken != null)
				return reader.Value.RequestedSecurityToken;

			tls.ProcessServerHello (reader.Value.BinaryExchange.Value);

			// send ClientKeyExchange
			WstRequestSecurityTokenResponse rstr =
				new WstRequestSecurityTokenResponse (SecurityTokenSerializer);
			rstr.Context = reader.Value.Context;
			rstr.BinaryExchange = new WstBinaryExchange (Constants.WstBinaryExchangeValueTls);
			rstr.BinaryExchange.Value = tls.ProcessClientKeyExchange ();

			request = Message.CreateMessage (IssuerBinding.MessageVersion, Constants.WstIssueReplyAction, rstr);
			request.Headers.ReplyTo = new EndpointAddress (Constants.WsaAnonymousUri);
			request.Headers.To = TargetAddress.Uri;

			buffer = request.CreateBufferedCopy (0x10000);
			tlsctx.StoreMessage (buffer.CreateMessage ().GetReaderAtBodyContents ());
//Console.WriteLine (System.Text.Encoding.UTF8.GetString (tlsctx.GetC14NResults ()));

			// FIXME: regeneration of this instance is somehow required, but should not be.
			proxy = new WSTrustSecurityTokenServiceProxy (
				IssuerBinding, IssuerAddress);
			response = proxy.IssueReply (buffer.CreateMessage ());
			// FIXME: use correct limitation
			buffer = response.CreateBufferedCopy (0x10000);

			WstRequestSecurityTokenResponseCollection coll =
				new WstRequestSecurityTokenResponseCollection ();
			coll.Read (Constants.WstTlsnegoProofTokenType, buffer.CreateMessage ().GetReaderAtBodyContents (), SecurityTokenSerializer, null);
			if (coll.Responses.Count != 2)
				throw new SecurityNegotiationException (String.Format ("Expected response is RequestSecurityTokenResponseCollection which contains two RequestSecurityTokenResponse items, but it actually contains {0} items", coll.Responses.Count));

			WstRequestSecurityTokenResponse r = coll.Responses [0];
			tls.ProcessServerFinished (r.BinaryExchange.Value);
			SecurityContextSecurityToken sctSrc =
				r.RequestedSecurityToken;

#if false // FIXME: should this final RSTR included in RSTRC considered too?
			XmlDocument doc = new XmlDocument ();
			doc.PreserveWhitespace = true;
			using (XmlDictionaryWriter dw = XmlDictionaryWriter.CreateDictionaryWriter (doc.CreateNavigator ().AppendChild ())) {
				if (r == null) throw new Exception ("r");
				if (dw == null) throw new Exception ("dw");
				r.WriteBodyContents (dw);
			}
			tlsctx.StoreMessage (XmlDictionaryReader.CreateDictionaryReader (new XmlNodeReader (doc)));
#endif

			// the RequestedProofToken is represented as 32 bytes
			// of TLS ApplicationData.
			// - According to WSE2 doc, it is *the* key, but not
			//   sure it also applies to WCF.
			// - WSS4J also seems to store the encryped shared key.
			// - (Important) It seems that without tls decryption,
			//   .NET fails to recover the key.
			byte [] proof = tls.ProcessApplicationData (
				(byte []) r.RequestedProofToken);
			byte [] key = proof;

			// Authenticate token.

			byte [] actual = coll.Responses [1].Authenticator;
			if (actual == null)
				throw new SecurityNegotiationException ("Token authenticator is expected in the RequestSecurityTokenResponse but not found.");

			if (coll.Responses [0].Context != contextId)
				throw new SecurityNegotiationException ("The context Id does not match with that of the corresponding token authenticator.");

			// H = sha1(exc14n(RST..RSTRs))
			byte [] hash = SHA1.Create ().ComputeHash (tlsctx.GetC14NResults ());
			byte [] referent = tls.CreateHash (key, hash, "AUTH-HASH");
			/*
Console.WriteLine (System.Text.Encoding.ASCII.GetString (tlsctx.GetC14NResults ()));
Console.Write ("Hash: ");
foreach (byte b in hash) Console.Write ("{0:X02} ", b); Console.WriteLine ();
Console.Write ("Referent: ");
foreach (byte b in referent) Console.Write ("{0:X02} ", b); Console.WriteLine ();
Console.Write ("Actual: ");
foreach (byte b in actual) Console.Write ("{0:X02} ", b); Console.WriteLine ();
Console.Write ("Proof: ");
foreach (byte b in proof) Console.Write ("{0:X02} ", b); Console.WriteLine ();
			*/
			bool mismatch = referent.Length != actual.Length;
			if (!mismatch)
				for (int i = 0; i < referent.Length; i++)
					if (referent [i] != actual [i])
						mismatch = true;

			if (mismatch)
				throw new SecurityNegotiationException ("The CombinedHash does not match the expected value.");

			return sctSrc;
		}