wiki:T12_Security/WS-Security

Version 31 (modified by pjkersha, 13 years ago) (diff)

--

Conversion of NDG Security WS Interfaces to use WS-Security

Current Status

The Alpha version of the s/w uses message level security based on pyXMLSec and ZSI. WSDL interface message arguments are signed and or encrypted before dispatch.

Reasons for Change

  • Current solution is bespoke. A more standards based solution is preferred.
  • DEWS project requires use of WS-Security
  • Standardised interface will enable smoother interoperation with clients written in other languages such as Java
  • A secondary issue is that pyXMLSec can be difficult to use. It would be helpful to remove it as dependency
  • pyGridWare + ZSI may give an off the shelf solution.

Approaches to a Solution

  • Investigate pyGridWare and experiment with examples
  • Implement custom solution for WS-Security but using ZSI - This would enable an interface according to what we need with minimal dependencies on other packages.
  • Look at IBM WebSphere - to be used with DEWS project. Check WS-Security support and how best to interface to it.

XML Signature

pyGridWare uses sha package for digest generation and M2Crypto for signing. A DOM based canonicalisation algorithm written by Rich Salz has been added to ZSI (ZSI.wstools.c14n). This gets a mention on a Python mailing list from May 2002:  http://mail.python.org/pipermail/xml-sig/2001-May/005462.html

Custom Signature Code

Objective: emulate digital signature using the above and validate against pyXMLSec Version.

pyXMLSec has been used in NDG up until now with enveloped signature e.g. for signed Attribute Certificates. For WS-Security we need to be able to use a reference instead, set to the particular part of the SOAP message body to be signed.

  • Modified pyXMLSec sign3.py test code to sign an externally referenced XML doc.
  • Written test code adapted from pyGridWare GssSignatureHandler to verify the above. This uses the canonicalization algorithm from ZSI.wstools.c14n and M2Crypto for verification:
from M2Crypto import X509, BIO, RSA

x509Cert = # Get cert from wsse header ...
        
# Extract RSA public key from the cert
rsaPubKey = x509Cert.get_pubkey().get_rsa()
        
# Apply the signature verification
verify = rsaPubKey.verify(signedInfoDigest, signature)
  • (21/08/06) Test sign code working with test version of verify and pyXMLSec verify code. Care is needed with namespace declarations and canonicalization. It seems that all namespaces should be included in a document subset whether they're referenced or not. See Spec ( http://www.w3.org/TR/xml-c14n)

Integration into ZSI

How best to integrate signature code into ZSI?

For WS client side, ZSI.Binding.Send has sig_handler keyword which can be assigned to a signature handler class. This must implement sign and verify methods. These both take the same single argument of a ZSI.writer.SoapWriter instance. verify indicates an invalid signature by raising an exception. GssSignatureHandler the pyGridWare handler class raises a VerifyError type.

For the server side there doesn't seem to be an explicit place holder for a signature handler so it would seem to be a more complicated as how to best verify inbound messages and sign outbound ones. Server side methods have access to the ZSI.parse.ParsedSoap instance which contains a dom member variable which would enable checking of content for verify.

For signing responses the best solution seems to be to sub class from ZSI.ServiceContainer.SOAPRequestHandler with an overloaded version of do_POST to include code to sign an outbound message. This has been implemented. ZSI.dispatch._Dispatch is a standalone function rather than a method of a class. In order to custom then, it was necessary to make a copy of this and get a derived version of ZSI.ServiceContainer.SOAPRequestHandler to call it. The custom _Dispatch method contains code to sign the outbound message. Currently, X.509 cert and private key arguments are hard coded until a suitable way can be found to pass these variables in.

The current status (01/09/06) is a working web service with SignatureHandler class signing/verifying messages to and from client and server.

Conversation with Joshua Boverhof (08/09/06): SOAPRequestHandler is an older piece of code left in because some people still make use of it. Use Twisted with mechanism to pass security handler instead.

Above code uses RPC style SOAP - will need to move to SOAP messaging style. All newer code uses document literal style for WSDL.

XML libraries, XPath and Canonicalization

ZSI provides an ElementProxy class interface for XML handling for SOAP messages. This inherits from a MessageInterface class. This would seem to enable the underlying Python XML libraries used to be changed easily. By default it uses PyXML DOM library. pyGridWare makes use of the 4Suite add-ons for extra performance.

Implementations for XPath and Canonicalization are important factors for consideration. There is a DOM based canonicalization algorithm available with ZSI. - Doesn't work with mini-dom?? -

ElementTree has been used project wide for NDG, prefered for its fast performance and pythonic style interface. However, there doesn't appear to be a canonicalization algorithm available for it or XPath support for attribute searches. findall can be used to search for elements but not element attributes. The latter is important with WS-Security for locating elements in the SOAP message for signatures or encryption.

pyGridWare includes an ElementTree based ElementProxy class but this appears to be incomplete. There is no canonicalization method and other issues resolve.

lxml is an implementation of the ElementTree API but using libxml2 and xslt underneath ( http://www.thescripts.com/forum/thread162575.html). XPath and canonicalization are supported. Performance appears to be comparable.

 http://codespeak.net/lxml/

The drawback is the addition of more dependencies. A core objective is to reduce the number of dependencies :/

XML Encryption

Looking at RSA encryption with M2Crypto: M2Crypto.RSA.public_encrypt crashes when it makes a call to the check_key method. This occurs when the RSA key is loaded from an X.509 cert.:

from M2Crypto import X509, RSA

x509Cert = X509.load_cert(certFilePath)

# Extract RSA public key from the cert
rsaPubKey = x509Cert.get_pubkey().get_rsa()
 
# Crashes HERE   
encryptedData = rsaPubKey.public_encrypt(data, RSA.pkcs1_padding)    

Tried recompiling and re-installing M2Crypto on two different machines but same result. As a fudge, commented out check_key call in public_encrypt.

Test Web Service using encryption

[12/09/06] Completed test web service program with client and server encrypting/decrypting messages:

 http://proj.badc.rl.ac.uk/ndg/browser/TI12-security/trunk/python/Tests/xmlsec/WS-Security?rev=1510

It uses Wrapped key Encryption i.e. the target content is encrypted with a shared key and this itself is encrypted with the public key of the recipient. Shared key encryption was carried out with the AES algorithm using the Python  Crypto library. Encryption is carried out only not encryption and signature. Combining the two is a later task.

Padding Input Data for Shared Key Encryption

Algorithms including AES require that the length of the data to be encrypted be a multiple of the algorithms block size. There is a standard way to do this for XML encryption specified in:  http://www.w3.org/TR/xmlenc-core/#sec-Alg-Block

With pyCrypto, no assumption is made and the padding must be added manually.

Validate against pyXMLSec code

Check the above against the pyXMLSec code as a form of validation. pyXMLSec e.g.s use enveloped style rather than reference list pointing to document elements that are encrypted. Write a test script to output the former in order to validate the result.

[20/09/06] Working version:

  • generate encrypted message and decrypted using pyXMLSec code (fixed when added correct padding for multiple of block size - last byte is set equal to the number of padding bytes.
  • pyXMLSec encrypted message decrypted with test code

WSDL + WS-Security?

The existing system uses WSDL so it would desirable to keep with this when integrating WS-Security. WS-PolicyAttachment standard would seem to cover what we need but is it too new for the s/w support tools to be there?

From contacts with WebSphere technical sales it seems it's not possible at the moment. Adding WS-Security may have to be a manual process:

 http://www-128.ibm.com/developerworks/webservices/library/ws-security.html#N1022C

Conversation with Joshua Boverhof (08/09/06): pyGridWare does use document literal style WSDL with ZSI. Current code simply signs the whole of SOAP message body. It doesn't sign individual fields.

[22/09/06] Updated ZSI from official 2.0_rc2 release to release 1252 from the Sourceforge pywebsvcs SubVersion? repository. pyGridWare now works and successfully created test code using pyGridWare wsdl2web which creates a WS using Twisted.

Also adapted the Echo WSDL example from the ZSI 1252 release. Created a document literal style WSDL from the existing RPC encoded NDG SimpleCA WSDL and created client and server code adapting from the ZSI Echo example. Also added in signature handling code for client and server: the server side has wsdl2dispatch generated code which includes a class which inherits from ZSI.ServiceContainer.ServiceInterface. This includes stubs for sign and verify methods which can be overridden as required to provide server side digital signature functionality.