[NSS] (Network Security Services) is library and tool set implementing cryptographic services. It supports SSL v2 and v3, TLS, PKCS #5, PKCS #7, PKCS #11, PKCS #12, S/MIME, X.509 v3 certificates, and other security standards. NSS is a Mozilla project and is widely used in Mozilla projects and elsewhere. NSS has a long track record of FIPS 140 certification. NSS is a competing alternative to OpenSSL. Unlike OpenSSL NSS is designed with secure key management at it's heart providing good integration with smart cards and other hardware based security solutions. Many organizations, especially government entities require NSS as the crypto provider.
Currently in OpenStatck crypto services are provided by OpenSSL. The use of OpenSSL is built directly into the code base. This project will factor out the crypto provider into a configurable option permitting a deployment to choose a preferred crypto provider. OpenSSL will remain the default. The refactoring will should allow the use of other crypto providers to be integrated easily in the future, for example GnuTLS.
in-process library calls vs. sub-process forking
Python bindings for OpenSSL operations are either virtually non-existent or incomplete. The approach to date has been to invoke an OpenSSL command by forking a sub-process. This is both inefficient and has the potential to leak security sensitive information via process parameters. It is preferred to use (in-process) library calls to perform cryptographic operations.
Advantages of in-process library calls:
- much more efficient
- less likely to leak security information
- better failure diagnostic (API errors are typically mapped to 1 or 2 command exit values)
- more flexible (command utilities usually only offer a subset of options available in the API)
The work involved breaks down into a series of staged steps. The following attempts to explain how each of these staged steps would be approached.
Significant pieces of crypto code are duplicated between keystone and keystoneclient. Unfortunately currently there is no mechanism by which keystone and keystoneclient can share common code. This is very unfortunate because two very similar code bases have to be maintained in parallel.
Crypto is most heavily used in Keystone. Keystone creates and manages X509 certificates and keys used for SSL/TLS as well as object signing and verification. Python-keystoneclient consumes some of these and implements almost identical code in a variety of places.
Because keystone has more complex crypto it will be modified first and serve as a model for crypto code in keystoneclient. Then eventually the two code bases should be merged into one common code base shared between keystone and keystone client.
At one high level view the staging of work is:
- Modify keystone
- Port portions of keystone code from step 1 to keystoneclient
- Merge 1 and 2 into common code base.
Stage 1: Separate Crypto Provider Classes
- Factor out existing OpenSSL'isms. The current code exposes some things which are unique to OpenSSL and have no direct corollary in other crypto implementations.
- Factor out OpenSSL operations into OpenSSL crypto provider class derived from generic crypto provider class.
- Add configuration support to select OpenSSL as crypto provider.
- Verify all unit tests run successfully with OpenSSL as crypto provider.
- Implement NSS crypto provider class
- Update unit tests to exercise both OpenSSL and NSS providers
Stage 2: Repeat Stage 1 for keystoneclient
The steps in Stage 1 have to be repeated for keystoneclient. This should be simpler because the work done in Stage 1 can copied/ported into the keystoneclient code base.
Stage 3: In-process library calls
Refactor the Crypto Provider classes into a common base class and 2 sub-classes. One subclass provides an implementation of sub-process calling model (the previous existing work) and the other subclass implements the same functionality using in-process library calls.
At the moment only NSS is envisioned or in-process library calling because at the moment NSS is the only crypto provider with an extensive Python binding.
The basic steps are:
- Split crypto provider class to allow sub-classes implementing either in-process or sub-process calling.
- Update unit test to select and use different calling models, initially fix unit tests to invoke the existing sub-processing calling model. Make sure all tests pass.
- Implement in-process calling for NSS crypto provider. Update unit tests to iterate over both calling models.
Staged Approach Summary
The work items break down into a number of distinct independent steps. They can be viewed as a series of nested loops. The nesting order can be rearranged if need be. For example factoring out common code into a shared module could be performed at a variety of locations in the staging steps.