This package provides a binding for the Network Security Services (NSS) library. Because NSS directly uses the Netscape Portable Runtime (NSPR) the binding also provides support for NSPR. There is an inherent conflict between NSPR and Python, please see the Issues section for more detail.
General documentation on NSS can be found here:
General documentation on NSPR can be found here:
Please note, the documentation included with this package already encapsultes most of the information at the above two URL's, but is specific to the python binding of NSS/NSPR. It is suggested you refer to the python-nss documentation.
Most of the names and symbols in the NSS/NSPR C API have been kept in the nss-python binding and should be instantly familar or recognizable. Python has different naming conventions and the nss-python binding has adhered to the python naming convensions, Classes are camel case, otherwise symbols are all lower case with words seperated by underscores. The constants used by NSS/NSPR in C API have been imported literally to add the programmer who might be referring to the Mozilla NSS/NSPR documentation and/or header files or who is porting an existing C application to python. Minor other changes have been made in the interest of being "Pythonic".
Some elements of the binding have been deprecated because of lessons learned along the way. The following emit deprecation warnings and should not be used, they will be removed in a subsequent release.
NSS stores it's certificates and private keys in a security database unlike OpenSSL which references it's certificates and keys via file pathnames. This means unless you already have an NSS Certificate Database (CertDB) the first order of business will be to create one. When a NSS application initializes itself it will need to specify the path to the CertDB (see "Things All NSS programs must do").
The CertDB is created and manipulated by the command line utilities certutil and modutil. Both of these programs are part of the nss-tools RPM. Documentation for these tools can be found here: http://www.mozilla.org/projects/security/pki/nss/tools
Here is an example of creating a CertDB and populating it. In the example the CertDB will be created under the directory "./pki", the CA will be called "myca", the database password will be "myca", and the server's hostname will be "myhost.example.com".
Create the database:
certutil -N -d ./pki
This creates a new database under the directory ./pki
Create a root CA certificate:
certutil -d ./pki -S -s "CN=myca" -n myca -x -t "CTu,C,C" -m 1
This creates an individual certificate and adds it to the certificate database with a subject of "CN=myca", a nickname of "myca", trust flags indicating for SSL indicating it can issue server certificates (C), can issue client certificates (T), and the certificate can be used for authentication and signing (u). For email and object signing it's trusted to create server certificates. The certificate serial number is set to 1.
Create a server certificate and sign it. Our example server will use this:
certutil -d pki -S -c myca -s "CN=myhost.example.com" -n myhost -t "u,u,u" -m 2
This creates an individual certificate issued by the CA "myca" and adds it to the certificate database with a subject of "CN=myhost.example.com", a nickname of "myhost". The certificate serial number is set to 2.
Import public root CA's:
modutil -add ca_certs -libfile /usr/lib/libnssckbi.so -dbdir ./pki
This is necessary to verify certificates presented by a SSL server a NSS client might connect to. When verifying a certificate the NSS library will "walk the certificate chain" back to a root CA which must be trusted. This command imports the well known root CA's as a PKCS #11 module.
Import the NSS/NSPR modules:
from nss.error import NSPRError import nss.io as io import nss.nss as nss import nss.ssl as ssl
In the interest of code brevity we drop the leading "nss." from the module namespace.
Initialize NSS and indicate the certficate database (CertDB):
certdir = './pki' ssl.nssinit(certdir)
If you are implementing an SSL server call config_secure_server() (see ssl_example.py):
sock = ssl.SSLSocket(net_addr.family) sock.config_secure_server(server_cert, priv_key, server_cert_kea)
WARNING you must call config_secure_server() for SSL servers, if you do not call it the most likely result will be the NSS library will segfault (not pretty).
There are example programs in under "examples" in the documentation directory. On Fedora/RHEL/CentOS systems this will be /usr/share/doc/python-nss.
The ssl_example.py sample implements both a client and server in one script. You tell it whether to run as a client (-C) or a server (-S) when you invoke it. The sample shows many of the NSS/NSPR calls and fully implements basic non-SSL client/server using NSPR, SSL client/server using NSS, certificate validation, CertDB operations, and client authentication using certificates.
To get a list of command line options:
Using the above example certificate database server can be run like this:
ssl_example.py -S -c ./pki -n myhost
The client can be run like this:
ssl_example.py -C -c ./pki
The current partitioning of the NSS and NSPR API's into Python modules (i.e. the Python namespaces and their symbols) is a first cut and may not be ideal. One should be prepared for name changes as the binding matures.
NSPR vs. Python
An original design goal of NSS was to be portable, however NSS required access to many system level functions which can vary widely between platforms and OS's. Therefore NSPR was written to encapsulate system services such as IO, sockets, threads, timers, etc. into a common API to insulate NSS from the underlying platform.
In many respects Python and its collection of packages and modules provides the same type of platform independence for applications and libraries and provides it's own implementation of IO, sockets, threads, timers, etc.
Unfortunately NSPR's and Python's run time abstractions are not the same nor can either be configured to use a different underlying abstraction layer.
Currently the NSS binding utilizes only the NSPR abstraction layer. One consequence of this is it is not possible to create a Python socket and use it as the foundation for any NSS functions expecting a socket, or visa versa.
You must use the nss.io module to create and manipulate a socket used by NSS. You cannot pass this socket to any Python library function expecting a socket. The two are not compatible.
Here are some reasons for this incompatibility, perhaps in the future we can find a solution but the immediate goal of the NSS Python binding was to expose NSS through Python, not necessarily to solve the larger integration issue of Python run-time and NSPR run-time.
NSPR would like to hide the underlying platform socket (in the NSPR code this is called "osfd"). There are NSPR API's which will operate on osfd's
One can base a NSPR socket on an existing osfd via:
One can obtain the osfd in use by NSPR, either when the osfd was imported or because NSPR created the osfd itself via:
But note this function is not meant to be public in the NSPR API and is documented as being deprecated and carries an explicit warning against it's use.
Once NSPR gets a hold of an osfd it manipulates it in a manner as if it were the only owner of the osfd. Other native code (e.g. the CPython socket code) which operates on the fd may run afoul of NSPR belief it is the only code in the system operating on the fd. For example in CPython the non-blocking flag is directly set on the fd and non-blocking behavior is implemented by the OS. However, NSPR manages non-blocking behavior internally to the NSPR library eschewing direct OS support for non-blocking. Thus CPython and NSPR are in direct conflict over when and how non-blocking is set on an fd. Examples of this problem can be seen in the Python socket.makefile() operation which takes the fd belonging to a system socket, dups it, and calls fdopen() on the dup'ed fd to return a FILE stream (all Python file IO is based on file objects utilizing a FILE stream). However, the dup'ed fd does not share the same non-blocking flag, NSPR explicitly forces the flag off, Python wants to directly manipulate it. Dup'ed fd's share their flags thus if Python operates on the dup'ed fd returned by NSPR it's going to confuse NSPR. Likewise if one sets non-blocking via NSPR then Python won't honor the flag because Python is expecting the flag to be set on the fd, not in some other location (e.g. internal to NSPR).
Python's socket implementation is a very thin layer over the Berkely socket API. There is very little abstraction, thus Python and Python program expect to manipulate sockets directly via their fd's.
The error and exception model for Python sockets and SSL is an almost direct one-to-one mapping of the Posix and OpenSSL errors. But NSS uses NSPR errors, thus Python code which has exception handlers for sockets and SSL are expecting a complete different set of exceptions.
Python's SSL implementation is a very thin layer over the OpenSSL API, there is little abstraction. Thus there is a sizeable body of Python code which expects the OpenSSL model for IO ready and has exception handlers based on OpenSSL.
To be added
|Generated by Epydoc 3.0.1 on Mon May 13 10:58:11 2013||http://epydoc.sourceforge.net|