| Προφίλ του χρήστη NathanNate's Random StuffΙστολόγιοΛίστες | Βοήθεια |
|
|
04 Ιουλίου WSE Posts on the moveTo keep things more focused, future WSE posts will be on my new MSDN Blogs site. 01 Απριλίου Merkle's Puzzles and WSE Part 3Now we'll look at how to hook everything together and actually exchange messages. First both client and server need to reference the proper token managers in their config files (only the server needs the user name token manager): < securityTokenManager qname="wsse:UsernameToken" type="CustomUsernameTokenManager, merkle_service" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"/> <binarySecurityTokenManager type="MerkleTokenManager, merkletoken" valueType="http://tempuri.org/CustomToken#MerkleToken" />The server hosts a token issuer service and any other services that do the actual work. Since I'm using the code approach instead of policy all the methods take and return SoapEnvelopes so I can access the context and attach the proper tokens. The token issuer: [SoapActor("soap://tempuri.org/PuzzleIssuer")] public class PuzzleIssuer : SoapService{ public SoapEnvelope Issue(SoapEnvelope envIn) ... } The Issue method checks for a signature on the request and then returns the puzzles. The response is signed with request's signing token. [SoapActor("soap://tempuri.org/EchoService")] public class EchoService : SoapService{ public SoapEnvelope Echo(SoapEnvelope envIn) {
} This method checks that it was encrypted with a MerkleToken and signed. The response returns the same object passed in and is encrypted with the MerkleToken and signed with the UsernameToken. The UsernameToken and signatures can be encrypted as well. The client creates two proxies from SoapClient and uses these to send messages to the services: PuzzleIssuerClient p = new PuzzleIssuerClient(eprIssuer, ut, null);MerkleToken mToken = new MerkleToken(p.Issue().Value);MerkleClient m = new MerkleClient(eprEcho, ut, mToken);Console.WriteLine(m.Echo("blah")); The constructors for the proxies take 3 parameters, the endpoint reference, a signing token and an encrypting token. PuzzleIssuerClient requires a signing token and the MerkleClient requires both. The call to PuzzleIssuerClient.Issue handles the signing with the token it was constructed with. The call to MerkleClient handles signing and encryption including encryption of the signing token and signatures. It's easy to encrypt the body of a message: env.Context.Security.Tokens.Add(_encryptingToken); env.Context.Security.Elements.Add( new EncryptedData(_encryptingToken));But how do you encrypt other parts of the message? There seems to be a little trick to this.
Now the these EncryptedData objects can be added to the Elements collection as before. Merkle's Puzzles and WSE Part 2This part will focus on the custom MerkleToken created for this project. We start with some static data: private static Hashtable _mapKnownKeys = new Hashtable(); private static byte[][] _puzzles = null;The hashtable maps random numbers to keys. On the server this will have all the mappings since different clients will decrypt different puzzles it needs to look up any random number. On the client it will only contain the key(s) for the puzzle(s) it decrypted, so when it receives an encrypted response it's a quick look up to get obtain the key. This also populates the RawData property with what goes on the wire, something that looks like this: <BinaryKey><MerkleToken>puzzle number</MerkleToken><BinaryToken> _puzzles holds the set of puzzles and is exposed through a property. This should never change on the service. It's somewhat of a limitation on the client side since the client can only to talk to one service using MerkleTokens at a time. Constructors: public MerkleToken(byte[][] puzzles)public MerkleToken(XmlElement element)The first is used by the client after it obtains the set of puzzles. This constructor randomly selects a puzzle using RNGCryptoServiceProvider and launches a brute force attack to crack it. It then stores the random number and key to the static map and maintains the random number as member variable as well. This also populates the RawData property with what goes on the wire, something that looks like this: <BinaryKey><MerkleToken>puzzle number</MerkleToken><BinaryToken> The second constructor is used by the MerkleTokenManager when WSE finds a MerkleToken in a message and calls LoadTokenFromXml. The XmlElement looks like the RawData element created by the first constructor. The final token specific part I'll discuss is the Key property. This takes the random number, looks up the key and then creates an AES128 SymmetricKeyAlgorithm with its KeyBytes property set the key. The token object does the heavy lifting, in the next part we'll look at how the client and server actually use it. Merkle's Puzzles and WSE Part 1I'm slowly working my way through Applied Cryptography by Bruce Schneier, so I thought I'd write some entries on the stuff I find interesting and apply them to WSE if possible. Merkle's Puzzles were developed by Ralph Merkle in 1974 and are one of the first demonsttations of a public key cryptosystem. The public key consists of a set of n puzzles. Each puzzle contains a random number and a private key that encrypts that puzzle. To encrypt a message a client would randomly select a puzzle and then launch an attack to decrypt it. The message is encrypted with the private key and the ciphertext is sent along with the random number, which is in the clear. The server maintains a mapping of which random number was encrypted with which key, so to decrypt it simply looks up the key and decrypts it. If it takes the client n time to crack a puzzle, and since an eavesdropper doesn't know which puzzle the client selected, the eavesdropper has to crack all the puzzles. This would take n2 time, which is an advantage but a very small one in the cryptographic world and why Merkle's Puzzles are only of academic and historic interest. In that academic interest, I've implemented a MerkleToken using the custom token facilities available in WSE. The basic design is:
There's some obvious real world problems here that I'll describe here and then blissfully ignore.
I've restricted myself from using tokens besides UsernameToken and MerkleToken, since if they were available it makes using the MerkleToken sillier than it already is. This precludes encrypting the original token exchange. This is an artifact of the lack of any infrastructure like a Merkle certificate that could vouch that puzzles belong to the service and haven't been modified. This also means I couldn't use WSE's token issuing framework since unencrypted UsernameTokens are forbidden in RST's since WSE2 SP2. In the coming parts I'll actually get to some code. I used the CustomBinaryToken quick start from the WSE documentation. Since all the more advanced quick starts use asmx, I decided to do this over tcp instead. Also I used the code based approach instead of policy since I find it easier to experiment with code. 08 Μαρτίου So you want to send really big attachments using DIMEFirst of all these messages are buffered entirely in memory, so the amount of memory in a system bounds the size of attachment you can send. Through experimentation we've found for a message 100-135 MB, 1 GB of system memory is required, though your mileage may vary. Out of the box, the default maximum allowed size is 4 MB. To adjust this there are several config settings. If the service is hosted in ASP.NET, use the <httpRuntime> element in the system.web section. The interesting attributes are maxRequestLength and executionTimeout. maxRequestLength is the number of KB allowed, so the default is 4096 KB (4 MB). executionTimeout is the number of seconds until the request is killed. So to set the max to 400 MB and timeout to 10 minutes, it would look like this: <httpRuntime executionTimeout="600" maxRequestLength="409600"/> If the service is hosted in TCP, then WSE provides similar config entries: <microsoft.web.services2> executionTimeout and maxRequestLength both have the same units as their ASP.NET counterparts, but they have the extra option of specifying -1 to say no maximum length, and no timeout. Say you're successfully configured your service to handle large attachements, but some attachments are still too large and you can't just throw more memory at the problem. Now you'll have to write some code, specifically your own chunking algorithm. By splitting the attachment into chunks you can send several manageable attachments instead of one gargantuan attachment. 01 Μαρτίου How do you get a wsdl from a SoapService?WSE ships with a tool called WseWsdl2.exe that will create a proxy class from a wsdl file, but what if you want to look at the underlying wsdl generated by a SoapService? As has been noted elsewhere, it is simply a matter of sending an envelope with an action of http://schemas.microsoft.com/wse/2003/06/RequestDescription. Probably the easiest way to do that is to leverage the SoapClient class with something like this: public class WsdlProxy : SoapClient{ public WsdlProxy( Uri to ) : base( to ){} public WsdlProxy( EndpointReference epr ) : base( epr ){} public virtual SoapEnvelope RequestDescription() { new SoapEnvelope(); // you can use the SoapMethod attribute to set this instead env.Context.Addressing.Action = "http://schemas.microsoft.com/wse/2003/06/RequestDescription"; return base.SendRequestResponse("RequestDescription", env); } } After calling RequestDescription, the wsdl is in the Body.FirstChild member of the returned envelope. To construct the WsdlProxy, if the SoapService has a logical name (ie it uses the SoapActor attribute) as well as a physical name, create an EndpointReference and use that constructor, otherwise simply create a Uri constuct it that way. |
|
|