Author: atsushi
Date: 2007-03-22 10:34:16 -0500 (Thu, 22 Mar 2007)
New Revision: 74813
Modified:
trunk/olive/class/System.ServiceModel/System.ServiceModel.Security.Tokens/ChangeLog
trunk/olive/class/System.ServiceModel/System.ServiceModel.Security.Tokens/SslSecurityTokenAuthenticator.cs
trunk/olive/class/System.ServiceModel/System.ServiceModel.Security.Tokens/SslSecurityTokenProvider.cs
trunk/olive/class/System.ServiceModel/System.ServiceModel.Security.Tokens/TlsClientSession.cs
Log:
2007-03-22 Atsushi Enomoto <[EMAIL PROTECTED]>
* TlsClientSession.cs, SslSecurityTokenProvider.cs,
SslSecurityTokenAuthenticator.cs : added hash calculation support,
not working yet though (probably at service side).
Modified:
trunk/olive/class/System.ServiceModel/System.ServiceModel.Security.Tokens/ChangeLog
===================================================================
---
trunk/olive/class/System.ServiceModel/System.ServiceModel.Security.Tokens/ChangeLog
2007-03-22 15:29:11 UTC (rev 74812)
+++
trunk/olive/class/System.ServiceModel/System.ServiceModel.Security.Tokens/ChangeLog
2007-03-22 15:34:16 UTC (rev 74813)
@@ -1,3 +1,9 @@
+2007-03-22 Atsushi Enomoto <[EMAIL PROTECTED]>
+
+ * TlsClientSession.cs, SslSecurityTokenProvider.cs,
+ SslSecurityTokenAuthenticator.cs : added hash calculation support,
+ not working yet though (probably at service side).
+
2007-03-20 Atsushi Enomoto <[EMAIL PROTECTED]>
* SslSecurityTokenAuthenticator.cs : don't reuse ContextId for SCT.
Modified:
trunk/olive/class/System.ServiceModel/System.ServiceModel.Security.Tokens/SslSecurityTokenAuthenticator.cs
===================================================================
---
trunk/olive/class/System.ServiceModel/System.ServiceModel.Security.Tokens/SslSecurityTokenAuthenticator.cs
2007-03-22 15:29:11 UTC (rev 74812)
+++
trunk/olive/class/System.ServiceModel/System.ServiceModel.Security.Tokens/SslSecurityTokenAuthenticator.cs
2007-03-22 15:34:16 UTC (rev 74813)
@@ -28,12 +28,14 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
+using System.IO;
using System.Net.Security;
using System.IdentityModel.Policy;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
+using System.Security.Cryptography.Xml;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Security;
@@ -111,20 +113,52 @@
return ProcessClientKeyExchange (request);
}
- Dictionary<string,TlsServerSession> sessions =
- new Dictionary<string,TlsServerSession> ();
+ class TlsServerSessionInfo
+ {
+ public TlsServerSessionInfo (string context,
TlsServerSession tls)
+ {
+ ContextId = context;
+ Tls = tls;
+ }
+ public string ContextId;
+ public TlsServerSession Tls;
+ public MemoryStream Messages = new MemoryStream ();
+ }
+
+ Dictionary<string,TlsServerSessionInfo> sessions =
+ new Dictionary<string,TlsServerSessionInfo> ();
+
+ void AppendNegotiationMessageXml (XmlReader reader,
TlsServerSessionInfo tlsInfo)
+ {
+ XmlDsigExcC14NTransform t = new XmlDsigExcC14NTransform
();
+ XmlDocument doc = new XmlDocument ();
+ doc.PreserveWhitespace = true;
+ reader.MoveToContent ();
+ doc.AppendChild (doc.ReadNode (reader));
+ t.LoadInput (doc);
+ MemoryStream stream = (MemoryStream) t.GetOutput ();
+ byte [] bytes = stream.ToArray ();
+ tlsInfo.Messages.Write (bytes, 0, bytes.Length);
+ }
+
Message ProcessClientHello (Message request)
{
+ // FIXME: use correct buffer size
+ MessageBuffer buffer = request.CreateBufferedCopy
(0x10000);
WSTrustRequestSecurityTokenReader reader =
- new WSTrustRequestSecurityTokenReader
(request.GetReaderAtBodyContents (), SecurityTokenSerializer);
+ new WSTrustRequestSecurityTokenReader
(buffer.CreateMessage ().GetReaderAtBodyContents (), SecurityTokenSerializer);
reader.Read ();
if (sessions.ContainsKey (reader.Value.Context))
throw new InvalidOperationException
(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);
@@ -135,25 +169,39 @@
Message reply = Message.CreateMessage (request.Version,
Constants.WstIssueReplyAction, rstr);
reply.Headers.RelatesTo = request.Headers.MessageId;
- sessions [reader.Value.Context] = tls;
+ // FIXME: use correct buffer size
+ buffer = reply.CreateBufferedCopy (0x10000);
+ AppendNegotiationMessageXml (buffer.CreateMessage
().GetReaderAtBodyContents (), tlsInfo);
- return reply;
+ sessions [reader.Value.Context] = tlsInfo;
+
+ return buffer.CreateMessage ();
}
Message ProcessClientKeyExchange (Message request)
{
+ // FIXME: use correct buffer size
+ MessageBuffer buffer = request.CreateBufferedCopy
(0x10000);
WSTrustRequestSecurityTokenResponseReader reader =
- new WSTrustRequestSecurityTokenResponseReader
(request.GetReaderAtBodyContents (), SecurityTokenSerializer, null);
+ new WSTrustRequestSecurityTokenResponseReader
(buffer.CreateMessage ().GetReaderAtBodyContents (), SecurityTokenSerializer,
null);
reader.Read ();
- TlsServerSession tls;
- if (!sessions.TryGetValue (reader.Value.Context, out
tls))
+ TlsServerSessionInfo tlsInfo;
+ if (!sessions.TryGetValue (reader.Value.Context, out
tlsInfo))
throw new InvalidOperationException
(String.Format ("The context '{0}' does not exist in this SSL negotiation
manager", reader.Value.Context));
+ TlsServerSession tls = tlsInfo.Tls;
+
+ AppendNegotiationMessageXml (buffer.CreateMessage
().GetReaderAtBodyContents (), tlsInfo);
+//Console.WriteLine (System.Text.Encoding.UTF8.GetString
(tlsInfo.Messages.ToArray ()));
+
tls.ProcessClientKeyExchange
(reader.Value.BinaryExchange.Value);
byte [] serverFinished = tls.ProcessServerFinished ();
- RijndaelManaged aes = new RijndaelManaged ();
+ // The shared key is computed as:
+ //
P_SHA1(encrypted_key,SHA1(exc14n(RST..RSTRs))+"CK-HASH")
+ byte [] hash = SHA1.Create ().ComputeHash
(tlsInfo.Messages.GetBuffer (), 0, (int) tlsInfo.Messages.Length);
+ byte [] ckhash = tls.CreateHash (tls.MasterSecret,
hash, "CK-HASH");
WstRequestSecurityTokenResponseCollection col =
new WstRequestSecurityTokenResponseCollection
();
@@ -168,14 +216,14 @@
// (do not use sslnego context here.)
new UniqueId (),
"uuid-" + Guid.NewGuid (),
- aes.Key,
+ ckhash,
from,
// FIXME: use
LocalServiceSecuritySettings.NegotiationTimeout
from.AddHours (8),
null,
owner.Manager.ServiceCredentials.SecureConversationAuthentication.SecurityStateEncoder);
rstr.RequestedSecurityToken = sct;
- rstr.RequestedProofToken = tls.ProcessApplicationData
(aes.Key);
+ rstr.RequestedProofToken = tls.ProcessApplicationData
(ckhash);
rstr.RequestedAttachedReference = new
LocalIdKeyIdentifierClause (sct.Id);
rstr.RequestedUnattachedReference = new
SecurityContextKeyIdentifierClause (sct.ContextId, null);
WstLifetime lt = new WstLifetime ();
@@ -188,10 +236,10 @@
col.Responses.Add (rstr);
- // FIXME: add authenticator
+ // Authenticator is mandatory for MS sslnego.
rstr = new WstRequestSecurityTokenResponse
(SecurityTokenSerializer);
rstr.Context = reader.Value.Context;
- rstr.Authenticator = tls.CreateAuthHash (aes.Key);
+ rstr.Authenticator = tls.CreateHash (key, hash,
"AUTH-HASH");
col.Responses.Add (rstr);
sessions.Remove (reader.Value.Context);
Modified:
trunk/olive/class/System.ServiceModel/System.ServiceModel.Security.Tokens/SslSecurityTokenProvider.cs
===================================================================
---
trunk/olive/class/System.ServiceModel/System.ServiceModel.Security.Tokens/SslSecurityTokenProvider.cs
2007-03-22 15:29:11 UTC (rev 74812)
+++
trunk/olive/class/System.ServiceModel/System.ServiceModel.Security.Tokens/SslSecurityTokenProvider.cs
2007-03-22 15:34:16 UTC (rev 74813)
@@ -33,6 +33,7 @@
using System.IdentityModel.Tokens;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
+using System.Security.Cryptography.Xml;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
@@ -71,8 +72,32 @@
{
}
+ class TlsnegoClientSessionContext
+ {
+ XmlDocument doc = new XmlDocument ();
+ XmlDsigExcC14NTransform t = new XmlDsigExcC14NTransform
();
+ MemoryStream stream = new MemoryStream ();
+
+ public void StoreMessage (XmlReader reader)
+ {
+ doc.RemoveAll ();
+ doc.AppendChild (doc.ReadNode (reader));
+ t.LoadInput (doc);
+ MemoryStream s = (MemoryStream) t.GetOutput ();
+ byte [] bytes = s.ToArray ();
+ stream.Write (bytes, 0, bytes.Length);
+ }
+
+ public byte [] GetC14NResults ()
+ {
+ return stream.ToArray ();
+ }
+ }
+
public SecurityToken GetToken (TimeSpan timeout)
{
+ TlsnegoClientSessionContext tlsctx =
+ new TlsnegoClientSessionContext ();
TlsClientSession tls = new TlsClientSession
(IssuerAddress.Uri.ToString ());
WstRequestSecurityToken rst =
new WstRequestSecurityToken ();
@@ -85,11 +110,17 @@
request.Headers.MessageId = new UniqueId ();
request.Headers.ReplyTo = new EndpointAddress
(Constants.WsaAnonymousUri);
request.Headers.To = TargetAddress.Uri;
- Message response = proxy.Issue (request);
+ 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
(response.GetReaderAtBodyContents (), SecurityTokenSerializer, null);
+ new WSTrustRequestSecurityTokenResponseReader
(buffer.CreateMessage ().GetReaderAtBodyContents (), SecurityTokenSerializer,
null);
reader.Read ();
if (reader.Value.RequestedSecurityToken != null)
return reader.Value.RequestedSecurityToken;
@@ -106,34 +137,50 @@
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 (request);
+ response = proxy.IssueReply (buffer.CreateMessage ());
+ // FIXME: use correct limitation
+ buffer = response.CreateBufferedCopy (0x10000);
+ // don't store this message in tlsctx (it's not part
+ // of exchange)
-MessageBuffer bugg = response.CreateBufferedCopy (10000);
-response = bugg.CreateMessage ();
-Console.WriteLine (bugg.CreateMessage ());
-
// FIXME: support simple RSTR
WstRequestSecurityTokenResponseCollection coll =
new WstRequestSecurityTokenResponseCollection
();
- coll.Read (response.GetReaderAtBodyContents (),
SecurityTokenSerializer, null);
+ coll.Read (buffer.CreateMessage
().GetReaderAtBodyContents (), SecurityTokenSerializer, null);
WstRequestSecurityTokenResponse r = coll.Responses [0];
tls.ProcessServerFinished (r.BinaryExchange.Value);
SecurityContextSecurityToken sctSrc =
r.RequestedSecurityToken;
- // the RequestedProofToken looks like below:
- // 17 03 01 00 30 1A 37 0A 80 3D 5E F7 6B 54 FA A0 FA 1B
- // C2 D6 B8 DB F0 4D E5 62 85 A7 31 0C 8E F9 F4 D9 5C 35
- // 99 DA C7 BE 45 8B 58 A1 B3 D0 B0 F8 8E C3 1C 46 A0
- // This looks like a TLS ApplicationData which consists
- // of 32 bytes of data. It smells like *the* shared key.
+ // the RequestedProofToken is represented as 32 bytes
+ // of TLS ApplicationData.
byte [] key = tls.ProcessApplicationData (
(byte []) r.RequestedProofToken);
+ byte [] actual = coll.Responses.Count > 1 ?
coll.Responses [1].Authenticator : null;
+ if (actual == null)
+ throw new MessageSecurityException ("Token
authenticator is expected in the RequestSecurityTokenResponse but not found.");
+ // H = sha1(exc14n(RST..RSTRs))
+
+ byte [] hash = SHA1.Create ().ComputeHash
(tlsctx.GetC14NResults ());
+ byte [] referent = tls.CreateHash (tls.MasterSecret,
hash, "AUTH-HASH");
+ 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 MessageSecurityException ("The
CombinedHash does not match the expected value.");
+
// FIXME: get correct parameter values.
SecurityContextSecurityToken sct = new
SecurityContextSecurityToken (sctSrc.ContextId, sctSrc.Id, key,
r.Lifetime.Created, r.Lifetime.Expires, null,
Modified:
trunk/olive/class/System.ServiceModel/System.ServiceModel.Security.Tokens/TlsClientSession.cs
===================================================================
---
trunk/olive/class/System.ServiceModel/System.ServiceModel.Security.Tokens/TlsClientSession.cs
2007-03-22 15:29:11 UTC (rev 74812)
+++
trunk/olive/class/System.ServiceModel/System.ServiceModel.Security.Tokens/TlsClientSession.cs
2007-03-22 15:34:16 UTC (rev 74813)
@@ -46,17 +46,20 @@
get { return Context.MasterSecret; }
}
- public byte [] CreateAuthHash (byte [] key)
+ public byte [] CreateHashAlt (byte [] key, byte [] seedSrc,
string label)
{
- string label = "AUTH-HASH";
- byte [] keyhash = SHA1.Create ().ComputeHash (key);
byte [] labelBytes = Encoding.UTF8.GetBytes (label);
- byte [] seed = new byte [keyhash.Length +
labelBytes.Length];
- Array.Copy (keyhash, seed, keyhash.Length);
- Array.Copy (labelBytes, 0, seed, keyhash.Length,
labelBytes.Length);
+ byte [] seed = new byte [seedSrc.Length +
labelBytes.Length];
+ Array.Copy (seedSrc, seed, seedSrc.Length);
+ Array.Copy (labelBytes, 0, seed, seedSrc.Length,
labelBytes.Length);
return Context.Current.Cipher.Expand ("SHA1", key,
seed, 256 / 8);
}
+ public byte [] CreateHash (byte [] key, byte [] seed, string
label)
+ {
+ return Context.Current.Cipher.PRF (key, label, seed,
256 / 8);
+ }
+
protected void WriteHandshake (MemoryStream ms)
{
Context.SupportedCiphers =
CipherSuiteFactory.GetSupportedCiphers (SecurityProtocolType.Tls);
_______________________________________________
Mono-patches maillist - [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches