Skip to main content

Articles

Featured Products

Windows Mobile Developer Controls
Windows Mobile Developer Controls
Stay in touch using the DEVBUSS RSS feeds.
 

News

Windows Mobile Developer Controls
Windows Mobile Developer Controls

SmartPhone (SP) and WebService Enhancements (WSE) with .NETcf

Written by casey chesnut  [author's bio]  [read 47304 times]
Edited by Derek

Download the code

Page 1  Page 2  Page 3  Page 4 

WoTe

Write once, Test everywhere !?!? ... I knew C# looked familiar :) The encryption to support WSE entails having an enhanced PROV_RSA_FULL provider found on most Pocket PC PCs, including PPC 2002, but not on the 2002 emulator. For PPC 2000, this can be added by installing the enhanced encryption pack. Although my Sys.Sec.Crypt library supports the DSA algorithm with the PROV_DSS_DH provider found on SP 2003 and PPC 2003, it is not yet necessary for making WSE2 calls. I extended the .NETcf crypto bits to look for if CryptoApi, the Enhanced Provider, and DSA are available.

I have tested the /spCrypt libraries on the PPC 2003 and CE emulators and got working results. Same goes for this articles unit tests with SP1 installed. Initial testing on my PPC 2002 device (Audiovox Maestro) showed some missing functions with Guid and Random # generation that can be overcome by using different methods. There was an unnecessary Crypto call being made (CryptProtectData) that resulted in a MissingMethodException. One way of doing HmacSha1 would throw a BAD_ALGID when destroying the key, but HMAC can also be done with multiple SHA1 calls. And RC2 symmetric encryption did not interop with the full framework, although it does on the emulators for SP 2003, PPC 2003, and CE .NET. So the variables are Device, OS, CryptoApi, and Service Pack ... and this should all be tested to get the codebase to the lowest common denominator. To help with this, I wrote a WoTe class to find Device, OS, and CLR info.

  • Device - CE, PocketPC, SmartPhone
  • OS - PPC 2000, PPC 2002, PPC 2003, SP 2002, SP 2003, CE 4.1, CE 4.2
  • CLR and ServicePack - .NETcf, SP1, SP2, ... come on Whidbey! 
  • CryptoApi - Base RSA Provider, Enhanced RSA Provider, DSA Provider

My current rule of thumb is to write all class libs as Windows CE projects. Then put a thin SmartPhone UI over that for testing. For kicks, I make PPC and CE WinForms project and run the SP UI in those environments as well. It ports with no changes, the only thing is that the menu operation is funny with a stylus. For even more kicks I will run those apps directly on a desktop computer. Hopefully device and desktop .resx files will be made compatible in Whidbey to make this easier. VS .NET could stand to do a better job of importing existing 'Web References' as well. Below are screen shots of the SmartPhone WSE unit test app running on a PPC 2003 emulator, CE .NET emulator, and on a desktop computer respectively.

WS-Security

This is the lowest level security specification for web services. There are a number of other security specifications which build upon this one (e.g. WS-Policy, WS-Trust, WS-SecureConversation). This one is the core, so it has to be built 1st. WS-Security is primarily used for 3 different scenarios: Authentication, Confidentiality, and Integrity. I will tackle these in this same order.

Authentication (Security Tokens)

This is actually the reason I began writing this article. 1st the Microsoft.com web service went public. It is basically a 'hello world' web service meaning it does not expose much functionality yet; but what made it interesting is that it required a UsernameToken SoapHeader to access the service. 2nd a Perl implementation of UsernameToken came out before a .NET one did, other than the WSE. Who cares if you are on the full framework, because you have the WSE, but .NETcf was out of luck. So I threw together a quick SoapHeader implementation and threw it out to the newsgroups. That was the decision point when I decided to attempt WSE for .NETcf again. NOTE you will have to supply your own username and password to access the service.

<Security xmlns="http://schemas.xmlsoap.org/ws/2002/07/secext" soap:mustUnderstand="1">
  <UsernameToken d4p1:Id="SecurityToken-2506db16-f1c8-2129-7f36-13b576716003" 
      xmlns:d4p1="http://schemas.xmlsoap.org/ws/2002/07/utility">
    <Username>Admin</Username> 
    <Password Type="wsse:PasswordDigest">ABC...=</Password> 
    <Nonce>yHZfWUJgSUMiUXcEdsPce2YXK6I=</Nonce> 
    <d4p1:Created>2003-11-08T00:05:19Z</d4p1:Created> 
  </UsernameToken>
</Security>

UsernameToken - Had already got it working against Microsoft.com, so I knew it was at least partially working. Next, I attempted to call the WSE2 sample. Before calling it, I modified the sample app to make sure it did not have to pass a Signature, and it worked without one. When I tried to call it, it kept throwing a SoapFault with 'The Soap Header Security was not understood'. Looking at the trace of the message from the WSE2 client, the 'wsse' namespace version was /2002/12/ instead of /2002/07/, so I upgraded mine and it worked. To test it more, I ran it against the WSE1 UsernameSigning sample, and it worked fine. I did have to modify the WS IsValid() method, so that it only looked for a UsernameToken SecurityToken, and not a Signature SecurityElement.

<Security xmlns="http://schemas.xmlsoap.org/ws/2002/12/secext" soap:mustUnderstand="1">
   ...
</Security>

BinaryToken - this is another type of Security Token that can be passed. For this one, all I did was read in an X509v3 certificate that was stored as a file on the device. Then I got the raw data and base64 encoded it. Passed it to an echo web service I wrote that just read the certificate and spit back the name. It worked with WSE2. Make sure you only pass around public certificates using this method.

<Security xmlns="http://schemas.xmlsoap.org/ws/2002/12/secext" soap:mustUnderstand="1"> 
  <BinarySecurityToken d4p1:Id="SecurityToken-acbfa8b0-ad6e-9164-3c25-4838ee2c2a68" 
    ValueType="wsse:X509v3" EncodingType="wsse:Base64Binary" 
    xmlns:d4p1="http://schemas.xmlsoap.org/ws/2002/07/utility"> 
      ABC...== 
  </BinarySecurityToken> 
</Security>

Other Security options include Kerberos and custom (binary & xml) tokens. I'd been reading about Kerberos and wanted to attempt it, but it requires my environment to have a domain, which I dont have the time to setup :(. My code would have to be extended to support these.

Confidentiality (Xml-Encryption)

The next level of difficulty is XmlEncryption. Started out with SymmetricEncryption from WSE1, because that sample does not exist for WSE2. Initially, the sample just encrypted the request, and the response came back in the clear. For the request, the SoapHeader needed a <Security\SecurityTokenReference> to be added along with the <EncryptedData> in the SoapBody. Made a SoapExtension to do this. The client application has to set some static objects on the SoapExtension that tells it how it wants to encrypt and decrypt, and the SoapExtension handles the rest. At 1st, the web service could not decrypt my messages, and was throwing back an XmlException. To test that my System.Security.Cryptography was really compatible, I grabbed the encrypted message from the WSE1 client trace, and decrypted it. This revealed that the messages were getting IV's appended to them, per the XENC spec when I looked it up. Added this logic to my code, and I got a successful response from the WebService. Then I extended the WS to send back an encrypted response as well, and updated the XmlEncryption SoapExtension do decrypt it.

xmlEncSymmReq.xml / xmlEncSymmRes.xml

Then I went to the WSE2 ResponseEncryption sample. In this one, the request sends a X509 certificate to the WS as a BinarySecurityToken in the SoapHeader; and the response returns an EncryptedKey in the SoapHeader, with EncryptedData in the SoapBody. For X509 Certificates, see the section below. The X509 cert has the public key that the WS uses to encrypt the response. The service creates a TripleDes session key to encrypt the SoapBody. That session key is then encrypted with the RSA public key from the certificate. On the client side, it discovers the EncryptedKey 1st, and uses the corresponding RSA private key to decrypt. That session key is then loaded into a TripleDesCryptoServiceProvider to decrypt the actual SoapBody. Works great. I did have to mod the web service to not require an XmlSignature at this time, and just look for the BinarySecurityToken directly.

xmlEncRes.xml

The final one is the WSE2 AsymmetricEncryption sample. The ResponseEncryption sample also uses Asymmetric encryption, but only the Response. This is the same, except it is for building the request, while the response comes back in plain text. One other difference is that instead of sending the public key as a BinarySecurityToken, it sends a KeyIdentifier. So the client generates a session key. That session key is encrypted with the servers public key and added as an EncryptedKey to the SoapHeader. That session key is also used to encrypt the SoapBody and replace it with an EncryptedData element.

xmlEncAsymmReq.xml

Right now it supports symmetric and asymmetric encryption. EncryptedKeys and EncryptedData. Named keys, X509 certificates, and known KeyIdentifiers. Encrypting the entire message, and also just a portion of the message using my LameXpath implementation (does anybody have a good Xpath imp. for .NETcf?). It would have to be extended to support referenced keys and arbitrary data, as well as multiple EncryptedKey and EncryptedData sections in a single message.

Previous Page  Next Page