add support for symmetric cipher encryption/decryption add test code for above some minor clean up in other areas git-svn-id: svn://10.0.0.236/trunk@258418 18797224-902f-48f8-a5cc-f745e15eee43
300 lines
12 KiB
Python
300 lines
12 KiB
Python
# ***** BEGIN LICENSE BLOCK *****
|
|
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
#
|
|
# The contents of this file are subject to the Mozilla Public License Version
|
|
# 1.1 (the "License"); you may not use this file except in compliance with
|
|
# the License. You may obtain a copy of the License at
|
|
# http://www.mozilla.org/MPL/
|
|
#
|
|
# Software distributed under the License is distributed on an "AS IS" basis,
|
|
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
# for the specific language governing rights and limitations under the
|
|
# License.
|
|
#
|
|
# The Original Code is a Python binding for Network Security Services (NSS).
|
|
#
|
|
# The Initial Developer of the Original Code is Red Hat, Inc.
|
|
# (Author: John Dennis <jdennis@redhat.com>)
|
|
#
|
|
# Portions created by the Initial Developer are Copyright (C) 2008,2009
|
|
# the Initial Developer. All Rights Reserved.
|
|
#
|
|
# Contributor(s):
|
|
#
|
|
# Alternatively, the contents of this file may be used under the terms of
|
|
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
# in which case the provisions of the GPL or the LGPL are applicable instead
|
|
# of those above. If you wish to allow use of your version of this file only
|
|
# under the terms of either the GPL or the LGPL, and not to allow others to
|
|
# use your version of this file under the terms of the MPL, indicate your
|
|
# decision by deleting the provisions above and replace them with the notice
|
|
# and other provisions required by the GPL or the LGPL. If you do not delete
|
|
# the provisions above, a recipient may use your version of this file under
|
|
# the terms of any one of the MPL, the GPL or the LGPL.
|
|
#
|
|
# ***** END LICENSE BLOCK *****
|
|
"""
|
|
============
|
|
Introduction
|
|
============
|
|
|
|
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:
|
|
|
|
http://www.mozilla.org/projects/security/pki/nss
|
|
|
|
General documentation on NSPR can be found here:
|
|
|
|
http://developer.mozilla.org/en/docs/NSPR_API_Reference
|
|
|
|
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".
|
|
|
|
===============
|
|
Getting Started
|
|
===============
|
|
|
|
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".
|
|
|
|
1. Create the database::
|
|
|
|
certutil -N -d ./pki
|
|
|
|
This creates a new database under the directory ./pki
|
|
|
|
2. 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.
|
|
|
|
|
|
3. 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 "C,C,C" -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.
|
|
|
|
4. 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.
|
|
|
|
|
|
===============================
|
|
Things All NSS programs must do
|
|
===============================
|
|
|
|
- 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()
|
|
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).
|
|
|
|
========
|
|
Examples
|
|
========
|
|
|
|
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::
|
|
|
|
ssl_example.py --help
|
|
|
|
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
|
|
|
|
======
|
|
Issues
|
|
======
|
|
|
|
- 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:
|
|
|
|
- PR_ImportFile()
|
|
- PR_ImportPipe()
|
|
- PR_ImportTCPSocket()
|
|
- PR_ImportUDPSocket()
|
|
|
|
- One can obtain the osfd in use by NSPR, either when the
|
|
osfd was imported or because NSPR created the osfd itself via:
|
|
|
|
- PR_FileDesc2NativeHandle();
|
|
|
|
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.
|
|
|
|
|
|
===
|
|
FAQ
|
|
===
|
|
|
|
To be added
|
|
|
|
"""
|
|
__version__ = '0.7'
|