Blame SOURCES/python-nss-0.14.1.patch

7f5c89
diff -N -u -r python-nss-0.14.0/doc/ChangeLog python-nss-0.14.1/doc/ChangeLog
7f5c89
--- python-nss-0.14.0/doc/ChangeLog	2013-05-02 17:29:27.000000000 -0400
7f5c89
+++ python-nss-0.14.1/doc/ChangeLog	2013-10-09 09:35:29.000000000 -0400
7f5c89
@@ -1,5 +1,37 @@
7f5c89
-2013-04-24  John Dennis  <jdennis@redhat.com> 0.14.0
7f5c89
-  External Changes
7f5c89
+2013-10-09  John Dennis  <jdennis@redhat.com> 0.14.1
7f5c89
+
7f5c89
+  Modifications only to tests and examples.
7f5c89
+
7f5c89
+  * Fix bug in ssl_example.py and test_client_server.py where complete
7f5c89
+    data was not read from socket. The Beast CVE fix in NSS causes
7f5c89
+    only one octet to be sent in the first socket packet and then the
7f5c89
+    remaining data is sent normally, this is known as 1/n-1 record
7f5c89
+    splitting. The example and test SSL code sent short messages and
7f5c89
+    then did a sock.recv(1024). We had always received the entire
7f5c89
+    message in one sock.recv() call because it was so short. But
7f5c89
+    sock.recv() does not guarantee how much data will be received,
7f5c89
+    thus this was a coding mistake. The solution is straight forward,
7f5c89
+    use newlines as a record separator and call sock.readline()
7f5c89
+    instead of sock.recv(). sock.readline() calls sock.recv()
7f5c89
+    internally until a complete line is read or the socket is closed.
7f5c89
+
7f5c89
+  * Rewrite setup_certs.py, it was written like an expect script
7f5c89
+    reacting to prompts read from a pseudo terminal but it was fragile
7f5c89
+    and would hang on some systems. New version uses temporary
7f5c89
+    password file and writes hardcoded responses to the stdin of
7f5c89
+    certuil and modutil.
7f5c89
+
7f5c89
+  * setup_certs now creates a new sql sytle NSS database (sql:pki)
7f5c89
+
7f5c89
+  * All tests and examples now load the sql:pki database. Command line
7f5c89
+    arg and variable changed from dbdir to db_name to reflect the
7f5c89
+    database specification is no longer just a directory.
7f5c89
+
7f5c89
+  * All command line process in test and examples now uses modern
7f5c89
+    argparse module instead of deprecated getopt and optparse. Some
7f5c89
+    command line args were tweaked.
7f5c89
+
7f5c89
+2013-04-24 John Dennis <jdennis@redhat.com> 0.14.0 External Changes
7f5c89
   ----------------
7f5c89
 
7f5c89
   The primary enhancements in this version is support of certifcate
7f5c89
diff -N -u -r python-nss-0.14.0/doc/examples/cert_dump.py python-nss-0.14.1/doc/examples/cert_dump.py
7f5c89
--- python-nss-0.14.0/doc/examples/cert_dump.py	2013-04-23 13:36:53.000000000 -0400
7f5c89
+++ python-nss-0.14.1/doc/examples/cert_dump.py	2013-10-08 12:59:24.000000000 -0400
7f5c89
@@ -18,10 +18,10 @@
7f5c89
 components of a cert.
7f5c89
 '''
7f5c89
 
7f5c89
+import argparse
7f5c89
+import getpass
7f5c89
 import os
7f5c89
 import sys
7f5c89
-import getopt
7f5c89
-import getpass
7f5c89
 
7f5c89
 from nss.error import NSPRError
7f5c89
 import nss.io as io
7f5c89
@@ -93,57 +93,34 @@
7f5c89
 
7f5c89
 # -----------------------------------------------------------------------------
7f5c89
 
7f5c89
-usage_str = '''
7f5c89
--p --pem        read the certifcate in PEM ascii format (default)
7f5c89
--d --der        read the certifcate in DER binary format
7f5c89
--P --print-cert print the cert using the internal rendering code
7f5c89
-'''
7f5c89
-
7f5c89
-def usage():
7f5c89
-    print usage_str
7f5c89
-
7f5c89
-try:
7f5c89
-    opts, args = getopt.getopt(sys.argv[1:], "hpdP",
7f5c89
-                               ["help", "pem", "der", "print-cert"])
7f5c89
-except getopt.GetoptError:
7f5c89
-    # print help information and exit:
7f5c89
-    usage()
7f5c89
-    sys.exit(2)
7f5c89
-
7f5c89
-
7f5c89
-filename = 'cert.der'
7f5c89
-is_pem_format = True
7f5c89
-print_cert = False
7f5c89
-
7f5c89
-for o, a in opts:
7f5c89
-    if o in ("-H", "--help"):
7f5c89
-        usage()
7f5c89
-        sys.exit()
7f5c89
-    elif o in ("-p", "--pem"):
7f5c89
-        is_pem_format = True
7f5c89
-    elif o in ("-d", "--der"):
7f5c89
-        is_pem_format = False
7f5c89
-    elif o in ("-P", "--print-cert"):
7f5c89
-        print_cert = True
7f5c89
-
7f5c89
-
7f5c89
-filename = sys.argv[1]
7f5c89
+parser = argparse.ArgumentParser(description='cert formatting example',
7f5c89
+                                 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
7f5c89
+parser.add_argument('-f', '--cert-format', choices=['pem', 'der'],
7f5c89
+                    help='format of input cert')
7f5c89
+parser.add_argument('-p', '--print-cert', action='store_true',
7f5c89
+                    help='print the cert using the internal rendering code')
7f5c89
+parser.add_argument('cert_file', nargs=1,
7f5c89
+                    help='input cert file to process')
7f5c89
+
7f5c89
+parser.set_defaults(cert_format='pem',
7f5c89
+                    print_cert=False
7f5c89
+                    )
7f5c89
+options = parser.parse_args()
7f5c89
 
7f5c89
 # Perform basic configuration and setup
7f5c89
 nss.nss_init_nodb()
7f5c89
 
7f5c89
-if len(args):
7f5c89
-    filename = args[0]
7f5c89
+filename = options.cert_file[0]
7f5c89
 
7f5c89
 print "certificate filename=%s" % (filename)
7f5c89
 
7f5c89
 # Read the certificate as DER encoded data
7f5c89
-si = nss.read_der_from_file(filename, is_pem_format)
7f5c89
+si = nss.read_der_from_file(filename, options.cert_format == 'pem')
7f5c89
 # Parse the DER encoded data returning a Certificate object
7f5c89
 cert = nss.Certificate(si)
7f5c89
 
7f5c89
 # Useful for comparing the internal cert rendering to what this script generates.
7f5c89
-if print_cert:
7f5c89
+if options.print_cert:
7f5c89
     print cert
7f5c89
 
7f5c89
 # Get the extension list from the certificate
7f5c89
diff -N -u -r python-nss-0.14.0/doc/examples/httplib_example.py python-nss-0.14.1/doc/examples/httplib_example.py
7f5c89
--- python-nss-0.14.0/doc/examples/httplib_example.py	2013-04-15 13:05:46.000000000 -0400
7f5c89
+++ python-nss-0.14.1/doc/examples/httplib_example.py	2013-10-08 13:04:03.000000000 -0400
7f5c89
@@ -4,13 +4,13 @@
7f5c89
 # License, v. 2.0. If a copy of the MPL was not distributed with this
7f5c89
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
7f5c89
 
7f5c89
-import sys
7f5c89
+import argparse
7f5c89
 import errno
7f5c89
-import getopt
7f5c89
-import urlparse
7f5c89
-import httplib
7f5c89
 import getpass
7f5c89
+import httplib
7f5c89
 import logging
7f5c89
+import sys
7f5c89
+import urlparse
7f5c89
 
7f5c89
 from nss.error import NSPRError
7f5c89
 import nss.io as io
7f5c89
@@ -19,14 +19,6 @@
7f5c89
 
7f5c89
 #------------------------------------------------------------------------------
7f5c89
 
7f5c89
-httplib_debug_level = 0
7f5c89
-logging_debug_level = logging.INFO
7f5c89
-certdir = 'pki'
7f5c89
-password = ''
7f5c89
-nickname = ''
7f5c89
-url = 'https://sourceforge.net/projects/python'
7f5c89
-use_ssl = True
7f5c89
-use_connection_class = True
7f5c89
 timeout_secs = 3
7f5c89
 
7f5c89
 #------------------------------------------------------------------------------
7f5c89
@@ -94,28 +86,6 @@
7f5c89
     logging.debug('cert valid %s for "%s"', cert_is_valid,  cert.subject)
7f5c89
     return cert_is_valid
7f5c89
 
7f5c89
-def client_auth_data_callback(ca_names, chosen_nickname, password, certdb):
7f5c89
-    cert = None
7f5c89
-    if chosen_nickname:
7f5c89
-        try:
7f5c89
-            cert = nss.find_cert_from_nickname(chosen_nickname, password)
7f5c89
-            priv_key = nss.find_key_by_any_cert(cert, password)
7f5c89
-            return cert, priv_key
7f5c89
-        except NSPRError:
7f5c89
-            return False
7f5c89
-    else:
7f5c89
-        nicknames = nss.get_cert_nicknames(certdb, nss.SEC_CERT_NICKNAMES_USER)
7f5c89
-        for nickname in nicknames:
7f5c89
-            try:
7f5c89
-                cert = nss.find_cert_from_nickname(nickname, password)
7f5c89
-                if cert.check_valid_times():
7f5c89
-                    if cert.has_signer_in_ca_names(ca_names):
7f5c89
-                        priv_key = nss.find_key_by_any_cert(cert, password)
7f5c89
-                        return cert, priv_key
7f5c89
-            except NSPRError:
7f5c89
-                return False
7f5c89
-        return False
7f5c89
-
7f5c89
 def password_callback(slot, retry, password):
7f5c89
     if not retry and password: return password
7f5c89
     return getpass.getpass("Enter password for %s: " % slot.token_name);
7f5c89
@@ -136,7 +106,7 @@
7f5c89
         if not dbdir:
7f5c89
             raise RuntimeError("dbdir is required")
7f5c89
 
7f5c89
-        logging.debug('%s init %s', self.__class__.__name__, host)
7f5c89
+        logging.debug('%s init host=%s dbdir=%s', self.__class__.__name__, host, dbdir)
7f5c89
         if not nss.nss_is_initialized(): nss.nss_init(dbdir)
7f5c89
         self.sock = None
7f5c89
         ssl.set_domestic_policy()
7f5c89
@@ -231,33 +201,46 @@
7f5c89
 #------------------------------------------------------------------------------
7f5c89
 
7f5c89
 
7f5c89
-opts, args = getopt.getopt(sys.argv[1:],
7f5c89
-                           'Dd:n:w:sScC',
7f5c89
-                           ['debuglevel','certdir=','nickname=','password=',
7f5c89
-                            'use-ssl', 'no-ssl', 'use-connection-class', 'no-connection-class'])
7f5c89
-for o, a in opts:
7f5c89
-    if o in('-D', '--httplib_debug_level'):
7f5c89
-        httplib_debug_level = httplib_debug_level + 1
7f5c89
-    elif o in ("-d", "--certdir"):
7f5c89
-        certdir = a
7f5c89
-    elif o in ("-n", "--nickname"):
7f5c89
-        nickname = a
7f5c89
-    elif o in ("-w", "--password"):
7f5c89
-        password = a
7f5c89
-    elif o in ("-s", "--use-ssl"):
7f5c89
-        use_ssl = True
7f5c89
-    elif o in ("-S", "--no-ssl"):
7f5c89
-        use_ssl = False
7f5c89
-    elif o in ("-c", "--use-connection-class"):
7f5c89
-        use_connection_class = True
7f5c89
-    elif o in ("-C", "--no-connection-class"):
7f5c89
-        use_connection_class = False
7f5c89
+parser = argparse.ArgumentParser(description='httplib example')
7f5c89
 
7f5c89
-if len(args) > 0:
7f5c89
-    url = args[0]
7f5c89
+parser.add_argument('-d', '--db-name',
7f5c89
+                    help='NSS database name (e.g. "sql:pki")')
7f5c89
 
7f5c89
+parser.add_argument('--db-passwd',
7f5c89
+                    help='NSS database password')
7f5c89
 
7f5c89
-if httplib_debug_level > 0:
7f5c89
+parser.add_argument('-s', '--ssl', dest='use_ssl', action='store_true',
7f5c89
+                    help='use SSL connection')
7f5c89
+
7f5c89
+parser.add_argument('-S', '--no-ssl', dest='use_ssl', action='store_false',
7f5c89
+                    help='do not use SSL connection')
7f5c89
+
7f5c89
+parser.add_argument('-c', '--connection-class', dest='use_connection_class', action='store_true',
7f5c89
+                    help='use connection class')
7f5c89
+
7f5c89
+parser.add_argument('-C', '--no-connection-class', dest='use_connection_class', action='store_false',
7f5c89
+                    help='do not use connection class')
7f5c89
+
7f5c89
+parser.add_argument('-D', '--httplib-debug-level', action='count',
7f5c89
+                    help='httplib debug level')
7f5c89
+
7f5c89
+parser.add_argument('url', nargs=1,
7f5c89
+                    help='URL to open (e.g. "https://sourceforge.net/projects/python"')
7f5c89
+
7f5c89
+parser.set_defaults(db_name = 'sql:pki',
7f5c89
+                    db_passwd = 'db_passwd',
7f5c89
+                    httplib_debug_level = 0,
7f5c89
+                    use_ssl = True,
7f5c89
+                    use_connection_class = True,
7f5c89
+                    )
7f5c89
+
7f5c89
+options = parser.parse_args()
7f5c89
+
7f5c89
+
7f5c89
+url = options.url[0]
7f5c89
+
7f5c89
+logging_debug_level = logging.INFO
7f5c89
+if options.httplib_debug_level > 0:
7f5c89
     logging_debug_level = logging.DEBUG
7f5c89
 else:
7f5c89
     logging_debug_level = logging.INFO
7f5c89
@@ -269,7 +252,7 @@
7f5c89
 # Perform basic configuration and setup
7f5c89
 
7f5c89
 url_components = urlparse.urlsplit(url)
7f5c89
-if use_ssl:
7f5c89
+if options.use_ssl:
7f5c89
     url_components.schema = 'https'
7f5c89
 else:
7f5c89
     url_components.schema = 'http'
7f5c89
@@ -280,14 +263,14 @@
7f5c89
     print "ERROR: bad url \"%s\"" % (url)
7f5c89
     sys.exit(1)
7f5c89
 
7f5c89
-if use_connection_class:
7f5c89
-    if use_ssl:
7f5c89
+if options.use_connection_class:
7f5c89
+    if options.use_ssl:
7f5c89
         logging.info("Start (using NSSConnection class) %s", url)
7f5c89
-        conn = NSSConnection(url_components.netloc, 443, dbdir="/etc/pki/nssdb")
7f5c89
+        conn = NSSConnection(url_components.netloc, 443, dbdir=options.db_name)
7f5c89
     else:
7f5c89
         logging.info("Start (using NSPRConnection class) %s", url)
7f5c89
         conn = NSPRConnection(url_components.netloc, 80)
7f5c89
-    conn.set_debuglevel(httplib_debug_level)
7f5c89
+    conn.set_debuglevel(options.httplib_debug_level)
7f5c89
     conn.connect()
7f5c89
     conn.request("GET", "/")
7f5c89
     response = conn.getresponse()
7f5c89
@@ -302,13 +285,13 @@
7f5c89
     print data
7f5c89
     conn.close()
7f5c89
 else:
7f5c89
-    if use_ssl:
7f5c89
+    if options.use_ssl:
7f5c89
         logging.info("Start (using NSSHTTPS class) %s", url)
7f5c89
-        h = NSSHTTPS(url_components.netloc, 443, dbdir="/etc/pki/nssdb")
7f5c89
+        h = NSSHTTPS(url_components.netloc, 443, dbdir=options.db_name)
7f5c89
     else:
7f5c89
         logging.info("Start (using NSPRHTTP class) %s", url)
7f5c89
         h = NSPRHTTP(url_components.netloc, 80)
7f5c89
-    h.set_debuglevel(httplib_debug_level)
7f5c89
+    h.set_debuglevel(options.httplib_debug_level)
7f5c89
     h.connect()
7f5c89
     h.putrequest('GET', '/')
7f5c89
     h.endheaders()
7f5c89
diff -N -u -r python-nss-0.14.0/doc/examples/ssl_example.py python-nss-0.14.1/doc/examples/ssl_example.py
7f5c89
--- python-nss-0.14.0/doc/examples/ssl_example.py	2013-04-15 13:05:46.000000000 -0400
7f5c89
+++ python-nss-0.14.1/doc/examples/ssl_example.py	2013-10-09 00:07:54.000000000 -0400
7f5c89
@@ -7,10 +7,10 @@
7f5c89
 import warnings
7f5c89
 warnings.simplefilter( "always", DeprecationWarning)
7f5c89
 
7f5c89
+import argparse
7f5c89
+import getpass
7f5c89
 import os
7f5c89
 import sys
7f5c89
-import getopt
7f5c89
-import getpass
7f5c89
 
7f5c89
 from nss.error import NSPRError
7f5c89
 import nss.io as io
7f5c89
@@ -24,19 +24,7 @@
7f5c89
 REQUEST_CLIENT_CERT_ALWAYS = 3
7f5c89
 REQUIRE_CLIENT_CERT_ALWAYS = 4
7f5c89
 
7f5c89
-# command line parameters, default them to something reasonable
7f5c89
-client = False
7f5c89
-server = False
7f5c89
-password = 'db_passwd'
7f5c89
-use_ssl = True
7f5c89
-client_cert_action = NO_CLIENT_CERT
7f5c89
-certdir = 'pki'
7f5c89
-hostname = os.uname()[1]
7f5c89
-server_nickname = 'test_server'
7f5c89
-client_nickname = 'test_user'
7f5c89
-port = 1234
7f5c89
 timeout_secs = 3
7f5c89
-family = io.PR_AF_UNSPEC
7f5c89
 
7f5c89
 # -----------------------------------------------------------------------------
7f5c89
 # Utility Functions
7f5c89
@@ -63,7 +51,7 @@
7f5c89
     if pin_args is None:
7f5c89
         pin_args = ()
7f5c89
 
7f5c89
-    print "cert:\n%s" % cert
7f5c89
+    print "peer cert:\n%s" % cert
7f5c89
 
7f5c89
     # Define how the cert is being used based upon the is_server flag.  This may
7f5c89
     # seem backwards, but isn't. If we're a server we're trying to validate a
7f5c89
@@ -149,30 +137,30 @@
7f5c89
     valid_addr = False
7f5c89
     # Get the IP Address of our server
7f5c89
     try:
7f5c89
-        addr_info = io.AddrInfo(hostname)
7f5c89
+        addr_info = io.AddrInfo(options.hostname)
7f5c89
     except Exception, e:
7f5c89
-        print "could not resolve host address \"%s\"" % hostname
7f5c89
+        print "could not resolve host address \"%s\"" % options.hostname
7f5c89
         return
7f5c89
 
7f5c89
     for net_addr in addr_info:
7f5c89
-        if family != io.PR_AF_UNSPEC:
7f5c89
-            if net_addr.family != family: continue
7f5c89
-        net_addr.port = port
7f5c89
+        if options.family != io.PR_AF_UNSPEC:
7f5c89
+            if net_addr.family != options.family: continue
7f5c89
+        net_addr.port = options.port
7f5c89
 
7f5c89
-        if use_ssl:
7f5c89
+        if options.use_ssl:
7f5c89
             sock = ssl.SSLSocket(net_addr.family)
7f5c89
 
7f5c89
             # Set client SSL socket options
7f5c89
             sock.set_ssl_option(ssl.SSL_SECURITY, True)
7f5c89
             sock.set_ssl_option(ssl.SSL_HANDSHAKE_AS_CLIENT, True)
7f5c89
-            sock.set_hostname(hostname)
7f5c89
+            sock.set_hostname(options.hostname)
7f5c89
 
7f5c89
             # Provide a callback which notifies us when the SSL handshake is complete
7f5c89
             sock.set_handshake_callback(handshake_callback)
7f5c89
 
7f5c89
             # Provide a callback to supply our client certificate info
7f5c89
-            sock.set_client_auth_data_callback(client_auth_data_callback, client_nickname,
7f5c89
-                                               password, nss.get_default_certdb())
7f5c89
+            sock.set_client_auth_data_callback(client_auth_data_callback, options.client_nickname,
7f5c89
+                                               options.password, nss.get_default_certdb())
7f5c89
 
7f5c89
             # Provide a callback to verify the servers certificate
7f5c89
             sock.set_auth_certificate_callback(auth_certificate_callback,
7f5c89
@@ -192,17 +180,18 @@
7f5c89
 
7f5c89
     if not valid_addr:
7f5c89
         print "Could not establish valid address for \"%s\" in family %s" % \
7f5c89
-        (hostname, io.addr_family_name(family))
7f5c89
+        (options.hostname, io.addr_family_name(options.family))
7f5c89
         return
7f5c89
 
7f5c89
     # Talk to the server
7f5c89
     try:
7f5c89
-        sock.send("Hello")
7f5c89
-        buf = sock.recv(1024)
7f5c89
+        sock.send('Hello' + '\n') # newline is protocol record separator
7f5c89
+        buf = sock.readline()
7f5c89
         if not buf:
7f5c89
             print "client lost connection"
7f5c89
             sock.close()
7f5c89
             return
7f5c89
+        buf = buf.rstrip()        # remove newline record separator
7f5c89
         print "client received: %s" % (buf)
7f5c89
     except Exception, e:
7f5c89
         print e.strerror
7f5c89
@@ -221,7 +210,7 @@
7f5c89
 
7f5c89
     try:
7f5c89
         sock.close()
7f5c89
-        if use_ssl:
7f5c89
+        if options.use_ssl:
7f5c89
             ssl.clear_session_cache()
7f5c89
     except Exception, e:
7f5c89
         print e
7f5c89
@@ -231,36 +220,34 @@
7f5c89
 # -----------------------------------------------------------------------------
7f5c89
 
7f5c89
 def Server():
7f5c89
-    global family
7f5c89
-
7f5c89
-    # Perform basic SSL server configuration
7f5c89
-    ssl.set_default_cipher_pref(ssl.SSL_RSA_WITH_NULL_MD5, True)
7f5c89
-    ssl.config_server_session_id_cache()
7f5c89
-
7f5c89
-    # Get our certificate and private key
7f5c89
-    server_cert = nss.find_cert_from_nickname(server_nickname, password)
7f5c89
-    priv_key = nss.find_key_by_any_cert(server_cert, password)
7f5c89
-    server_cert_kea = server_cert.find_kea_type();
7f5c89
-
7f5c89
-    print "server cert:\n%s" % server_cert
7f5c89
-
7f5c89
     # Setup an IP Address to listen on any of our interfaces
7f5c89
-    if family == io.PR_AF_UNSPEC:
7f5c89
-        family = io.PR_AF_INET
7f5c89
-    net_addr = io.NetworkAddress(io.PR_IpAddrAny, port, family)
7f5c89
+    if options.family == io.PR_AF_UNSPEC:
7f5c89
+        options.family = io.PR_AF_INET
7f5c89
+    net_addr = io.NetworkAddress(io.PR_IpAddrAny, options.port, options.family)
7f5c89
+
7f5c89
+    if options.use_ssl:
7f5c89
+        # Perform basic SSL server configuration
7f5c89
+        ssl.set_default_cipher_pref(ssl.SSL_RSA_WITH_NULL_MD5, True)
7f5c89
+        ssl.config_server_session_id_cache()
7f5c89
+
7f5c89
+        # Get our certificate and private key
7f5c89
+        server_cert = nss.find_cert_from_nickname(options.server_nickname, options.password)
7f5c89
+        priv_key = nss.find_key_by_any_cert(server_cert, options.password)
7f5c89
+        server_cert_kea = server_cert.find_kea_type();
7f5c89
+
7f5c89
+        print "server cert:\n%s" % server_cert
7f5c89
 
7f5c89
-    if use_ssl:
7f5c89
         sock = ssl.SSLSocket(net_addr.family)
7f5c89
 
7f5c89
         # Set server SSL socket options
7f5c89
-        sock.set_pkcs11_pin_arg(password)
7f5c89
+        sock.set_pkcs11_pin_arg(options.password)
7f5c89
         sock.set_ssl_option(ssl.SSL_SECURITY, True)
7f5c89
         sock.set_ssl_option(ssl.SSL_HANDSHAKE_AS_SERVER, True)
7f5c89
 
7f5c89
         # If we're doing client authentication then set it up
7f5c89
-        if client_cert_action >= REQUEST_CLIENT_CERT_ONCE:
7f5c89
+        if options.client_cert_action >= REQUEST_CLIENT_CERT_ONCE:
7f5c89
             sock.set_ssl_option(ssl.SSL_REQUEST_CERTIFICATE, True)
7f5c89
-        if client_cert_action == REQUIRE_CLIENT_CERT_ONCE:
7f5c89
+        if options.client_cert_action == REQUIRE_CLIENT_CERT_ONCE:
7f5c89
             sock.set_ssl_option(ssl.SSL_REQUIRE_CERTIFICATE, True)
7f5c89
         sock.set_auth_certificate_callback(auth_certificate_callback, nss.get_default_certdb())
7f5c89
 
7f5c89
@@ -278,7 +265,7 @@
7f5c89
     while True:
7f5c89
         # Accept a connection from a client
7f5c89
         client_sock, client_addr = sock.accept()
7f5c89
-        if use_ssl:
7f5c89
+        if options.use_ssl:
7f5c89
             client_sock.set_handshake_callback(handshake_callback)
7f5c89
 
7f5c89
         print "client connect from: %s" % (client_addr)
7f5c89
@@ -286,14 +273,15 @@
7f5c89
         while True:
7f5c89
             try:
7f5c89
                 # Handle the client connection
7f5c89
-                buf = client_sock.recv(1024)
7f5c89
+                buf = client_sock.readline()
7f5c89
                 if not buf:
7f5c89
                     print "server lost lost connection to %s" % (client_addr)
7f5c89
                     break
7f5c89
 
7f5c89
+                buf = buf.rstrip()                 # remove newline record separator
7f5c89
                 print "server received: %s" % (buf)
7f5c89
 
7f5c89
-                client_sock.send("Goodbye")
7f5c89
+                client_sock.send('Goodbye' + '\n') # newline is protocol record separator
7f5c89
                 try:
7f5c89
                     client_sock.shutdown(io.PR_SHUTDOWN_RCV)
7f5c89
                     client_sock.close()
7f5c89
@@ -308,7 +296,7 @@
7f5c89
     try:
7f5c89
         sock.shutdown()
7f5c89
         sock.close()
7f5c89
-        if use_ssl:
7f5c89
+        if options.use_ssl:
7f5c89
             ssl.shutdown_server_session_id_cache()
7f5c89
     except Exception, e:
7f5c89
         print e
7f5c89
@@ -316,141 +304,121 @@
7f5c89
 
7f5c89
 # -----------------------------------------------------------------------------
7f5c89
 
7f5c89
-usage_str = '''
7f5c89
--C --client     run as the client (default: %(client)s)
7f5c89
--S --server     run as the server (default: %(server)s)
7f5c89
--d --certdir    certificate directory (default: %(certdir)s)
7f5c89
--h --hostname   host to connect to (default: %(hostname)s)
7f5c89
--f --family     may be inet|inet6|unspec (default: %(family)s)
7f5c89
-                if unspec client tries all addresses returned by AddrInfo
7f5c89
-                          server binds to IPv4 "any" wildcard address
7f5c89
-                if inet   client tries IPv4 addresses returned by AddrInfo
7f5c89
-                          server binds to IPv4 "any" wildcard address
7f5c89
-                if inet6  client tries IPv6 addresses returned by AddrInfo
7f5c89
-                          server binds to IPv6 "any" wildcard address
7f5c89
--4 --inet       set family to inet (see family)
7f5c89
--6 --inet6      set family to inet6 (see family)
7f5c89
--n --server_nickname server certificate nickname (default: %(server_nickname)s)
7f5c89
--N --client_nickname client certificate nickname (default: %(client_nickname)s)
7f5c89
--w --password   certificate database password (default: %(password)s)
7f5c89
--p --port       host port (default: %(port)s)
7f5c89
--e --encrypt    use SSL (default) (default: %(encrypt)s)
7f5c89
--E --noencrypt  don't use SSL (default: %(noencrypt)s)
7f5c89
--f --require_cert_once (default: %(require_cert_once)s)
7f5c89
--F --require_cert_always (default: %(require_cert_always)s)
7f5c89
--r --request_cert_once (default: %(request_cert_once)s)
7f5c89
--R --request_cert_always (default: %(request_cert_always)s)
7f5c89
--H --help
7f5c89
-''' % {
7f5c89
-       'client'              : client,
7f5c89
-       'server'              : server,
7f5c89
-       'certdir'             : certdir,
7f5c89
-       'hostname'            : hostname,
7f5c89
-       'family'              : io.addr_family_name(family),
7f5c89
-       'server_nickname'     : server_nickname,
7f5c89
-       'client_nickname'     : client_nickname,
7f5c89
-       'password'            : password,
7f5c89
-       'port'                : port,
7f5c89
-       'encrypt'             : use_ssl is True,
7f5c89
-       'noencrypt'           : use_ssl is False,
7f5c89
-       'require_cert_once'   : client_cert_action == REQUIRE_CLIENT_CERT_ONCE,
7f5c89
-       'require_cert_always' : client_cert_action == REQUIRE_CLIENT_CERT_ALWAYS,
7f5c89
-       'request_cert_once'   : client_cert_action == REQUEST_CLIENT_CERT_ONCE,
7f5c89
-       'request_cert_always' : client_cert_action == REQUEST_CLIENT_CERT_ALWAYS,
7f5c89
-       }
7f5c89
-
7f5c89
-def usage():
7f5c89
-    print usage_str
7f5c89
-
7f5c89
-try:
7f5c89
-    opts, args = getopt.getopt(sys.argv[1:], "Hd:h:f:46n:N:w:p:CSeE",
7f5c89
-                               ["help", "certdir=", "hostname=",
7f5c89
-                                "family", "inet", "inet6",
7f5c89
-                                "server_nickname=", "client_nickname=",
7f5c89
-                                "password=", "port=",
7f5c89
-                                "client", "server", "encrypt", "noencrypt",
7f5c89
-                                "require_cert_once", "require_cert_always",
7f5c89
-                                "request_cert_once", "request_cert_always",
7f5c89
-                                ])
7f5c89
-except getopt.GetoptError:
7f5c89
-    # print help information and exit:
7f5c89
-    usage()
7f5c89
-    sys.exit(2)
7f5c89
-
7f5c89
-
7f5c89
-for o, a in opts:
7f5c89
-    if o in ("-d", "--certdir"):
7f5c89
-        certdir = a
7f5c89
-    elif o in ("-h", "--hostname"):
7f5c89
-        hostname = a
7f5c89
-    elif o in ("-f", "--family"):
7f5c89
-        if a == "inet":
7f5c89
+class FamilyArgAction(argparse.Action):
7f5c89
+    def __call__(self, parser, namespace, values, option_string=None):
7f5c89
+        value = values[0]
7f5c89
+        if value == "inet":
7f5c89
             family = io.PR_AF_INET
7f5c89
-        elif a == "inet6":
7f5c89
+        elif value == "inet6":
7f5c89
             family = io.PR_AF_INET6
7f5c89
-        elif a == "unspec":
7f5c89
+        elif value == "unspec":
7f5c89
             family = io.PR_AF_UNSPEC
7f5c89
         else:
7f5c89
-            print "unknown address family (%s)" % (a)
7f5c89
-            usage()
7f5c89
-            sys.exit()
7f5c89
-    elif o in ("-4", "--inet"):
7f5c89
-        family = io.PR_AF_INET
7f5c89
-    elif o in ("-6", "--inet6"):
7f5c89
-        family = io.PR_AF_INET6
7f5c89
-    elif o in ("-n", "--server_nickname"):
7f5c89
-        server_nickname = a
7f5c89
-    elif o in ("-N", "--client_nickname"):
7f5c89
-        client_nickname = a
7f5c89
-    elif o in ("-w", "--password"):
7f5c89
-        password = a
7f5c89
-    elif o in ("-p", "--port"):
7f5c89
-        port = int(a)
7f5c89
-    elif o in ("-C", "--client"):
7f5c89
-        client = True
7f5c89
-    elif o in ("-S", "--server"):
7f5c89
-        server = True
7f5c89
-    elif o in ("-e", "--encrypt"):
7f5c89
-        use_ssl = True
7f5c89
-    elif o in ("-E", "--noencrypt"):
7f5c89
-        use_ssl = False
7f5c89
-    elif o in ("--require_cert_once"):
7f5c89
-        client_cert_action = REQUIRE_CLIENT_CERT_ONCE
7f5c89
-    elif o in ("--require_cert_always"):
7f5c89
-        client_cert_action = REQUIRE_CLIENT_CERT_ALWAYS
7f5c89
-    elif o in ("--request_cert_once"):
7f5c89
-        client_cert_action = REQUEST_CLIENT_CERT_ONCE
7f5c89
-    elif o in ("--request_cert_always"):
7f5c89
-        client_cert_action = REQUEST_CLIENT_CERT_ALWAYS
7f5c89
-    elif o in ("-H", "--help"):
7f5c89
-        usage()
7f5c89
-        sys.exit()
7f5c89
-    else:
7f5c89
-        usage()
7f5c89
-        sys.exit()
7f5c89
+            raise argparse.ArgumentError(self, "unknown address family (%s)" % (value))
7f5c89
+        setattr(namespace, self.dest, family)
7f5c89
+
7f5c89
+parser = argparse.ArgumentParser(description='SSL example')
7f5c89
+
7f5c89
+parser.add_argument('-C', '--client', action='store_true',
7f5c89
+                    help='run as the client')
7f5c89
+
7f5c89
+parser.add_argument('-S', '--server', action='store_true',
7f5c89
+                    help='run as the server')
7f5c89
+
7f5c89
+parser.add_argument('-d', '--db-name',
7f5c89
+                    help='NSS database name (e.g. "sql:pki")')
7f5c89
+
7f5c89
+parser.add_argument('-H', '--hostname',
7f5c89
+                    help='host to connect to')
7f5c89
+
7f5c89
+parser.add_argument('-f', '--family',
7f5c89
+                    choices=['unspec', 'inet', 'inet6'],
7f5c89
+                    dest='family', action=FamilyArgAction, nargs=1,
7f5c89
+                    help='''
7f5c89
+                      If unspec client tries all addresses returned by AddrInfo,
7f5c89
+                      server binds to IPv4 "any" wildcard address.
7f5c89
+
7f5c89
+                      If inet client tries IPv4 addresses returned by AddrInfo,
7f5c89
+                      server binds to IPv4 "any" wildcard address.
7f5c89
+
7f5c89
+                      If inet6 client tries IPv6 addresses returned by AddrInfo,
7f5c89
+                      server binds to IPv6 "any" wildcard address''')
7f5c89
 
7f5c89
-if client and server:
7f5c89
+parser.add_argument('-4', '--inet',
7f5c89
+                    dest='family', action='store_const', const=io.PR_AF_INET,
7f5c89
+                    help='set family to inet (see family)')
7f5c89
+
7f5c89
+parser.add_argument('-6', '--inet6',
7f5c89
+                    dest='family', action='store_const', const=io.PR_AF_INET6,
7f5c89
+                    help='set family to inet6 (see family)')
7f5c89
+
7f5c89
+parser.add_argument('-n', '--server-nickname',
7f5c89
+                    help='server certificate nickname')
7f5c89
+
7f5c89
+parser.add_argument('-N', '--client-nickname',
7f5c89
+                    help='client certificate nickname')
7f5c89
+
7f5c89
+parser.add_argument('-w', '--password',
7f5c89
+                    help='certificate database password')
7f5c89
+
7f5c89
+parser.add_argument('-p', '--port', type=int,
7f5c89
+                    help='host port')
7f5c89
+
7f5c89
+parser.add_argument('-e', '--encrypt', dest='use_ssl', action='store_true',
7f5c89
+                    help='use SSL connection')
7f5c89
+
7f5c89
+parser.add_argument('-E', '--no-encrypt', dest='use_ssl', action='store_false',
7f5c89
+                    help='do not use SSL connection')
7f5c89
+
7f5c89
+parser.add_argument('--require-cert-once', dest='client_cert_action',
7f5c89
+                    action='store_const', const=REQUIRE_CLIENT_CERT_ONCE)
7f5c89
+
7f5c89
+parser.add_argument('--require-cert-always', dest='client_cert_action',
7f5c89
+                    action='store_const', const=REQUIRE_CLIENT_CERT_ALWAYS)
7f5c89
+
7f5c89
+parser.add_argument('--request-cert-once', dest='client_cert_action',
7f5c89
+                    action='store_const', const=REQUEST_CLIENT_CERT_ONCE)
7f5c89
+
7f5c89
+parser.add_argument('--request-cert-always', dest='client_cert_action',
7f5c89
+                    action='store_const', const=REQUEST_CLIENT_CERT_ALWAYS)
7f5c89
+
7f5c89
+parser.set_defaults(client = False,
7f5c89
+                    server = False,
7f5c89
+                    db_name = 'sql:pki',
7f5c89
+                    hostname = os.uname()[1],
7f5c89
+                    family = io.PR_AF_UNSPEC,
7f5c89
+                    server_nickname = 'test_server',
7f5c89
+                    client_nickname = 'test_user',
7f5c89
+                    password = 'db_passwd',
7f5c89
+                    port = 1234,
7f5c89
+                    use_ssl = True,
7f5c89
+                    client_cert_action = NO_CLIENT_CERT,
7f5c89
+                   )
7f5c89
+
7f5c89
+options = parser.parse_args()
7f5c89
+
7f5c89
+if options.client and options.server:
7f5c89
     print "can't be both client and server"
7f5c89
     sys.exit(1)
7f5c89
-if not (client or server):
7f5c89
+if not (options.client or options.server):
7f5c89
     print "must be one of client or server"
7f5c89
     sys.exit(1)
7f5c89
 
7f5c89
 # Perform basic configuration and setup
7f5c89
-if certdir is None:
7f5c89
-    nss.nss_init_nodb()
7f5c89
+if options.use_ssl:
7f5c89
+    nss.nss_init(options.db_name)
7f5c89
 else:
7f5c89
-    nss.nss_init(certdir)
7f5c89
+    nss.nss_init_nodb()
7f5c89
 
7f5c89
 ssl.set_domestic_policy()
7f5c89
 nss.set_password_callback(password_callback)
7f5c89
 
7f5c89
 # Run as a client or as a server
7f5c89
-if client:
7f5c89
+if options.client:
7f5c89
     print "starting as client"
7f5c89
     Client()
7f5c89
 
7f5c89
-if server:
7f5c89
+if options.server:
7f5c89
     print "starting as server"
7f5c89
     Server()
7f5c89
 
7f5c89
@@ -458,4 +426,3 @@
7f5c89
     nss.nss_shutdown()
7f5c89
 except Exception, e:
7f5c89
     print e
7f5c89
-
7f5c89
diff -N -u -r python-nss-0.14.0/doc/examples/verify_cert.py python-nss-0.14.1/doc/examples/verify_cert.py
7f5c89
--- python-nss-0.14.0/doc/examples/verify_cert.py	2013-04-15 13:05:46.000000000 -0400
7f5c89
+++ python-nss-0.14.1/doc/examples/verify_cert.py	2013-10-08 13:04:51.000000000 -0400
7f5c89
@@ -1,7 +1,7 @@
7f5c89
 #!/usr/bin/python
7f5c89
 
7f5c89
+import argparse
7f5c89
 import sys
7f5c89
-import optparse
7f5c89
 
7f5c89
 import nss.nss as nss
7f5c89
 import nss.error as nss_error
7f5c89
@@ -75,75 +75,74 @@
7f5c89
     lines.extend(nss.make_line_fmt_tuples(level, msg))
7f5c89
     lines.extend(obj.format_lines(level+1))
7f5c89
     return nss.indented_format(lines)
7f5c89
-    
7f5c89
+
7f5c89
 
7f5c89
 #-------------------------------------------------------------------------------
7f5c89
 
7f5c89
 def main():
7f5c89
-    # Command line argument processing
7f5c89
-    parser = optparse.OptionParser()
7f5c89
-
7f5c89
-    parser.set_defaults(dbdir = '/etc/pki/nssdb',
7f5c89
-                        db_passwd = 'db_passwd',
7f5c89
-                        input_format = 'pem',
7f5c89
-                        check_sig = True,
7f5c89
-                        print_cert = False,
7f5c89
-                        with_log = True,
7f5c89
-                        check_ca = True,
7f5c89
-                        )
7f5c89
+    global options
7f5c89
 
7f5c89
-    param_group = optparse.OptionGroup(parser, 'NSS Database',
7f5c89
-                                       'Specify & control the NSS Database')
7f5c89
+    parser = argparse.ArgumentParser(description='certificate validation example')
7f5c89
 
7f5c89
-    param_group.add_option('-d', '--dbdir', dest='dbdir',
7f5c89
-                           help='NSS database directory, default="%default"')
7f5c89
-    param_group.add_option('-P', '--db-passwd', dest='db_passwd',
7f5c89
-                           help='NSS database password, default="%default"')
7f5c89
+    # === NSS Database Group ===
7f5c89
+    group = parser.add_argument_group('NSS Database',
7f5c89
+                                      'Specify & control the NSS Database')
7f5c89
+    group.add_argument('-d', '--db-name',
7f5c89
+                       help='NSS database name (e.g. "sql:pki")')
7f5c89
 
7f5c89
-    parser.add_option_group(param_group)
7f5c89
+    group.add_argument('-P', '--db-passwd',
7f5c89
+                       help='NSS database password')
7f5c89
 
7f5c89
-    param_group = optparse.OptionGroup(parser, 'Certificate',
7f5c89
-                                       'Specify how the certificate is loaded')
7f5c89
+    # === Certificate Group ===
7f5c89
+    group = parser.add_argument_group('Certificate',
7f5c89
+                                      'Specify how the certificate is loaded')
7f5c89
 
7f5c89
-    param_group.add_option('-f', '--file', dest='cert_filename',
7f5c89
-                           help='read cert from file')
7f5c89
-    param_group.add_option('--format', dest='input_format', choices=['pem', 'der'],
7f5c89
-                           help='import format for certificate (der|pem) default="%default"')
7f5c89
-    param_group.add_option('-n', '--nickname', dest='cert_nickname',
7f5c89
-                           help='load cert from NSS database by looking it up under this nickname')
7f5c89
+    group.add_argument('-f', '--file', dest='cert_filename',
7f5c89
+                       help='read cert from file')
7f5c89
 
7f5c89
+    group.add_argument('-F', '--input-format', choices=['pem', 'der'],
7f5c89
+                       help='format of input cert')
7f5c89
 
7f5c89
-    parser.add_option_group(param_group)
7f5c89
+    group.add_argument('-n', '--nickname', dest='cert_nickname',
7f5c89
+                       help='load cert from NSS database by looking it up under this nickname')
7f5c89
 
7f5c89
-    param_group = optparse.OptionGroup(parser, 'Validation',
7f5c89
-                                       'Control the validation')
7f5c89
+    # === Validation Group ===
7f5c89
+    group = parser.add_argument_group('Validation',
7f5c89
+                                      'Control the validation')
7f5c89
 
7f5c89
-    param_group.add_option('-u', '--usage', dest='cert_usage', action='append', choices=cert_usage_map.keys(),
7f5c89
-                           help='may be specified multiple times, default="CheckAllUsages", may be one of: %s' % ', '.join(sorted(cert_usage_map.keys())))
7f5c89
-    param_group.add_option('-c', '--check-sig', action='store_true', dest='check_sig',
7f5c89
-                           help='check signature default=%default')
7f5c89
-    param_group.add_option('-C', '--no-check-sig', action='store_false', dest='check_sig',
7f5c89
+    group.add_argument('-u', '--usage', dest='cert_usage', action='append', choices=cert_usage_map.keys(),
7f5c89
+                           help='certificate usage flags, may be specified multiple times')
7f5c89
+    group.add_argument('-c', '--check-sig', action='store_true', dest='check_sig',
7f5c89
                            help='check signature')
7f5c89
-    param_group.add_option('-l', '--log', action='store_true', dest='with_log',
7f5c89
-                           help='use verify log, default=%default')
7f5c89
-    param_group.add_option('-L', '--no-log', action='store_false', dest='with_log',
7f5c89
-                           help='use verify log, default=%default')
7f5c89
-    param_group.add_option('-a', '--check-ca', action='store_true', dest='check_ca',
7f5c89
-                           help='check if cert is CA, default=%default')
7f5c89
-    param_group.add_option('-A', '--no-check-ca', action='store_false', dest='check_ca',
7f5c89
-                           help='check if cert is CA, default=%default')
7f5c89
-
7f5c89
-    parser.add_option_group(param_group)
7f5c89
-
7f5c89
-    param_group = optparse.OptionGroup(parser, 'Miscellaneous',
7f5c89
-                                       'Miscellaneous options')
7f5c89
+    group.add_argument('-C', '--no-check-sig', action='store_false', dest='check_sig',
7f5c89
+                           help='do not check signature')
7f5c89
+    group.add_argument('-l', '--log', action='store_true', dest='with_log',
7f5c89
+                           help='use verify log')
7f5c89
+    group.add_argument('-L', '--no-log', action='store_false', dest='with_log',
7f5c89
+                           help='do not use verify log')
7f5c89
+    group.add_argument('-a', '--check-ca', action='store_true', dest='check_ca',
7f5c89
+                           help='check if cert is CA')
7f5c89
+    group.add_argument('-A', '--no-check-ca', action='store_false', dest='check_ca',
7f5c89
+                           help='do not check if cert is CA')
7f5c89
+
7f5c89
+    # === Miscellaneous Group ===
7f5c89
+    group = parser.add_argument_group('Miscellaneous',
7f5c89
+                                      'Miscellaneous options')
7f5c89
 
7f5c89
-    param_group.add_option('-p', '--print-cert', action='store_true', dest='print_cert',
7f5c89
-                           help='print the certificate in a friendly fashion, default=%default')
7f5c89
+    group.add_argument('-p', '--print-cert', action='store_true', dest='print_cert',
7f5c89
+                       help='print the certificate in a friendly fashion')
7f5c89
 
7f5c89
-    parser.add_option_group(param_group)
7f5c89
 
7f5c89
-    options, args = parser.parse_args()
7f5c89
+    parser.set_defaults(db_name = 'sql:pki',
7f5c89
+                        db_passwd = 'db_passwd',
7f5c89
+                        input_format = 'pem',
7f5c89
+                        check_sig = True,
7f5c89
+                        with_log = True,
7f5c89
+                        check_ca = True,
7f5c89
+                        print_cert = False,
7f5c89
+                        )
7f5c89
+
7f5c89
+    options = parser.parse_args()
7f5c89
 
7f5c89
     # Process the command line arguments
7f5c89
 
7f5c89
@@ -175,9 +174,9 @@
7f5c89
         return 1
7f5c89
 
7f5c89
     # Initialize NSS.
7f5c89
-    print indented_output('NSS Database', options.dbdir)
7f5c89
+    print indented_output('NSS Database', options.db_name)
7f5c89
     print
7f5c89
-    nss.nss_init(options.dbdir)
7f5c89
+    nss.nss_init(options.db_name)
7f5c89
     certdb = nss.get_default_certdb()
7f5c89
     nss.set_password_callback(password_callback)
7f5c89
 
7f5c89
@@ -194,7 +193,7 @@
7f5c89
         except Exception, e:
7f5c89
             print e
7f5c89
             print >>sys.stderr, 'Unable to load cert nickname "%s" from database "%s"' % \
7f5c89
-                (options.cert_nickname, options.dbdir)
7f5c89
+                (options.cert_nickname, options.db_name)
7f5c89
             return 1
7f5c89
 
7f5c89
     # Dump the cert if the user wants to see it
7f5c89
@@ -282,5 +281,3 @@
7f5c89
 #-------------------------------------------------------------------------------
7f5c89
 if __name__ == "__main__":
7f5c89
     sys.exit(main())
7f5c89
-
7f5c89
-
7f5c89
diff -N -u -r python-nss-0.14.0/doc/examples/verify_server.py python-nss-0.14.1/doc/examples/verify_server.py
7f5c89
--- python-nss-0.14.0/doc/examples/verify_server.py	2013-04-15 13:05:46.000000000 -0400
7f5c89
+++ python-nss-0.14.1/doc/examples/verify_server.py	2013-10-08 13:00:37.000000000 -0400
7f5c89
@@ -4,10 +4,10 @@
7f5c89
 # License, v. 2.0. If a copy of the MPL was not distributed with this
7f5c89
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
7f5c89
 
7f5c89
+import argparse
7f5c89
+import getpass
7f5c89
 import os
7f5c89
 import sys
7f5c89
-import getopt
7f5c89
-import getpass
7f5c89
 
7f5c89
 from nss.error import NSPRError
7f5c89
 import nss.io as io
7f5c89
@@ -16,11 +16,6 @@
7f5c89
 
7f5c89
 # -----------------------------------------------------------------------------
7f5c89
 
7f5c89
-# command line parameters, default them to something reasonable
7f5c89
-#certdir = '/etc/httpd/alias'
7f5c89
-certdir = '/etc/pki/nssdb'
7f5c89
-hostname = 'www.verisign.com'
7f5c89
-port = 443
7f5c89
 timeout_secs = 3
7f5c89
 
7f5c89
 request = '''\
7f5c89
@@ -104,18 +99,18 @@
7f5c89
     valid_addr = False
7f5c89
     # Get the IP Address of our server
7f5c89
     try:
7f5c89
-        addr_info = io.AddrInfo(hostname)
7f5c89
+        addr_info = io.AddrInfo(options.hostname)
7f5c89
     except:
7f5c89
-        print "ERROR: could not resolve hostname \"%s\"" % hostname
7f5c89
+        print "ERROR: could not resolve hostname \"%s\"" % options.hostname
7f5c89
         return
7f5c89
 
7f5c89
     for net_addr in addr_info:
7f5c89
-        net_addr.port = port
7f5c89
+        net_addr.port = options.port
7f5c89
         sock = ssl.SSLSocket(net_addr.family)
7f5c89
         # Set client SSL socket options
7f5c89
         sock.set_ssl_option(ssl.SSL_SECURITY, True)
7f5c89
         sock.set_ssl_option(ssl.SSL_HANDSHAKE_AS_CLIENT, True)
7f5c89
-        sock.set_hostname(hostname)
7f5c89
+        sock.set_hostname(options.hostname)
7f5c89
 
7f5c89
         # Provide a callback which notifies us when the SSL handshake is
7f5c89
         # complete
7f5c89
@@ -135,7 +130,7 @@
7f5c89
             continue
7f5c89
 
7f5c89
     if not valid_addr:
7f5c89
-        print "ERROR: could not connect to \"%s\"" % hostname
7f5c89
+        print "ERROR: could not connect to \"%s\"" % options.hostname
7f5c89
         return
7f5c89
 
7f5c89
     try:
7f5c89
@@ -158,48 +153,31 @@
7f5c89
 
7f5c89
 # -----------------------------------------------------------------------------
7f5c89
 
7f5c89
-usage_str = '''
7f5c89
--d --certdir    certificate directory (default: %(certdir)s)
7f5c89
--h --hostname   host to connect to (default: %(hostname)s)
7f5c89
--p --port       host port (default: %(port)s)
7f5c89
-''' % {
7f5c89
-       'certdir'             : certdir,
7f5c89
-       'hostname'            : hostname,
7f5c89
-       'port'                : port,
7f5c89
-       }
7f5c89
+parser = argparse.ArgumentParser(description='certificate verification example',
7f5c89
+                                 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
7f5c89
 
7f5c89
-def usage():
7f5c89
-    print usage_str
7f5c89
+parser.add_argument('-d', '--db-name',
7f5c89
+                    help='NSS database name (e.g. "sql:pki")')
7f5c89
 
7f5c89
-try:
7f5c89
-    opts, args = getopt.getopt(sys.argv[1:], "Hd:h:p:",
7f5c89
-                               ["help", "certdir=", "hostname=",
7f5c89
-                                "port=",
7f5c89
-                                ])
7f5c89
-except getopt.GetoptError:
7f5c89
-    # print help information and exit:
7f5c89
-    usage()
7f5c89
-    sys.exit(2)
7f5c89
-
7f5c89
-
7f5c89
-for o, a in opts:
7f5c89
-    if o in ("-d", "--certdir"):
7f5c89
-        certdir = a
7f5c89
-    if o in ("-h", "--hostname"):
7f5c89
-        hostname = a
7f5c89
-    if o in ("-p", "--port"):
7f5c89
-        port = int(a)
7f5c89
-    if o in ("-H", "--help"):
7f5c89
-        usage()
7f5c89
-        sys.exit()
7f5c89
+parser.add_argument('-H', '--hostname',
7f5c89
+                    help='host to connect to')
7f5c89
+
7f5c89
+parser.add_argument('-p', '--port', type=int,
7f5c89
+                    help='host port')
7f5c89
+
7f5c89
+parser.set_defaults(db_name = 'sql:pki',
7f5c89
+                    hostname = 'www.verisign.com',
7f5c89
+                    port = 443,
7f5c89
+                    )
7f5c89
+
7f5c89
+options = parser.parse_args()
7f5c89
 
7f5c89
 # Perform basic configuration and setup
7f5c89
 try:
7f5c89
-    nss.nss_init(certdir)
7f5c89
+    nss.nss_init(options.db_name)
7f5c89
     ssl.set_domestic_policy()
7f5c89
 except Exception, e:
7f5c89
     print >>sys.stderr, e.strerror
7f5c89
     sys.exit(1)
7f5c89
 
7f5c89
 client()
7f5c89
-
7f5c89
diff -N -u -r python-nss-0.14.0/src/__init__.py python-nss-0.14.1/src/__init__.py
7f5c89
--- python-nss-0.14.0/src/__init__.py	2013-04-24 16:30:26.000000000 -0400
7f5c89
+++ python-nss-0.14.1/src/__init__.py	2013-10-08 14:38:28.000000000 -0400
7f5c89
@@ -163,8 +163,8 @@
7f5c89
 
7f5c89
 - Initialize NSS and indicate the certficate database (CertDB)::
7f5c89
 
7f5c89
-    certdir = './pki'
7f5c89
-    ssl.nssinit(certdir)
7f5c89
+    db_name = 'sql:pki'
7f5c89
+    ssl.nssinit(db_name)
7f5c89
 
7f5c89
 - If you are implementing an SSL server call config_secure_server()
7f5c89
   (see ssl_example.py)::
7f5c89
@@ -244,7 +244,7 @@
7f5c89
     future we can find a solution but the immediate goal of the NSS
7f5c89
     Python binding was to expose NSS through Python, not necessarily
7f5c89
     to solve the larger integration issue of Python run-time and NSPR
7f5c89
-    run-time. 
7f5c89
+    run-time.
7f5c89
 
7f5c89
     - NSPR would like to hide the underlying platform socket (in the
7f5c89
       NSPR code this is called "osfd"). There are NSPR API's which
7f5c89
@@ -312,5 +312,4 @@
7f5c89
 To be added
7f5c89
 
7f5c89
 """
7f5c89
-__version__ = '0.14.0'
7f5c89
-
7f5c89
+__version__ = '0.14.1'
7f5c89
diff -N -u -r python-nss-0.14.0/test/run_tests python-nss-0.14.1/test/run_tests
7f5c89
--- python-nss-0.14.0/test/run_tests	2013-04-30 11:03:54.000000000 -0400
7f5c89
+++ python-nss-0.14.1/test/run_tests	2013-10-08 12:57:56.000000000 -0400
7f5c89
@@ -1,21 +1,13 @@
7f5c89
 #!/usr/bin/python
7f5c89
 
7f5c89
-import getopt
7f5c89
-import sys
7f5c89
+import argparse
7f5c89
 import os
7f5c89
+import sys
7f5c89
 import unittest
7f5c89
 from util import get_build_dir
7f5c89
 
7f5c89
 #-------------------------------------------------------------------------------
7f5c89
 
7f5c89
-prog_name = os.path.basename(sys.argv[0])
7f5c89
-
7f5c89
-config = {
7f5c89
-    'in_tree'          : True,
7f5c89
-}
7f5c89
-
7f5c89
-#-------------------------------------------------------------------------------
7f5c89
-
7f5c89
 def run_tests():
7f5c89
 
7f5c89
     import setup_certs
7f5c89
@@ -23,9 +15,11 @@
7f5c89
     import test_cipher
7f5c89
     import test_digest
7f5c89
     import test_pkcs12
7f5c89
+    import test_misc
7f5c89
+    import test_ocsp
7f5c89
     import test_client_server
7f5c89
 
7f5c89
-    setup_certs.setup_certs()
7f5c89
+    setup_certs.setup_certs([])
7f5c89
 
7f5c89
     loader = unittest.TestLoader()
7f5c89
     runner = unittest.TextTestRunner()
7f5c89
@@ -43,62 +37,19 @@
7f5c89
 
7f5c89
 #-------------------------------------------------------------------------------
7f5c89
 
7f5c89
-class Usage(Exception):
7f5c89
-    def __init__(self, msg):
7f5c89
-        self.msg = msg
7f5c89
-
7f5c89
-def usage():
7f5c89
-    'Print command help.'
7f5c89
-
7f5c89
-    return '''\
7f5c89
-%(prog_name)s [-i]
7f5c89
-
7f5c89
--h --help          print help
7f5c89
--i --installed     runs the test using installed libraries
7f5c89
-                   instead of "in tree" libraries
7f5c89
-
7f5c89
-Runs unit tests.
7f5c89
-By default test is done "in tree".
7f5c89
-
7f5c89
-Examples:
7f5c89
-
7f5c89
-Run test using libraries built in this tree
7f5c89
-%(prog_name)s
7f5c89
-
7f5c89
-Run post install test
7f5c89
-%(prog_name)s -i
7f5c89
-''' % {'prog_name' : prog_name,
7f5c89
-      }
7f5c89
-
7f5c89
-#-------------------------------------------------------------------------------
7f5c89
+def main():
7f5c89
+    parser = argparse.ArgumentParser(description='run the units (installed or in tree)')
7f5c89
+    parser.add_argument('-i', '--installed', action='store_false', dest='in_tree',
7f5c89
+                        help='run tests using installed library')
7f5c89
+    parser.add_argument('-t', '--in-tree', action='store_true', dest='in_tree',
7f5c89
+                        help='run tests using devel tree')
7f5c89
 
7f5c89
-def main(argv=None):
7f5c89
-    if argv is None:
7f5c89
-        argv = sys.argv
7f5c89
-
7f5c89
-    try:
7f5c89
-        try:
7f5c89
-            opts, args = getopt.getopt(argv[1:], 'hi',
7f5c89
-                                       ['help', 'installed',])
7f5c89
-        except getopt.GetoptError, e:
7f5c89
-            raise Usage(e)
7f5c89
-            return 2
7f5c89
-
7f5c89
-        for o, a in opts:
7f5c89
-            if o in ('-h', '--help'):
7f5c89
-                print >>sys.stdout, usage()
7f5c89
-                return 0
7f5c89
-            elif o in ('-i', '--installed'):
7f5c89
-                config['in_tree'] = False
7f5c89
-            else:
7f5c89
-                raise Usage("command argument '%s' not handled, internal error" % o)
7f5c89
-    except Usage, e:
7f5c89
-        print >>sys.stderr, e.msg
7f5c89
-        print >>sys.stderr, "for help use --help"
7f5c89
-        return 2
7f5c89
+    parser.set_defaults(in_tree = False,
7f5c89
+                        )
7f5c89
 
7f5c89
+    options = parser.parse_args()
7f5c89
 
7f5c89
-    if config['in_tree']:
7f5c89
+    if options.in_tree:
7f5c89
         # Run the tests "in the tree"
7f5c89
         # Rather than testing with installed versions run the test
7f5c89
         # with the package built in this tree.
7f5c89
diff -N -u -r python-nss-0.14.0/test/setup_certs.py python-nss-0.14.1/test/setup_certs.py
7f5c89
--- python-nss-0.14.0/test/setup_certs.py	2013-04-18 12:28:05.000000000 -0400
7f5c89
+++ python-nss-0.14.1/test/setup_certs.py	2013-10-17 11:07:09.000000000 -0400
7f5c89
@@ -1,345 +1,506 @@
7f5c89
 #!/usr/bin/python
7f5c89
 
7f5c89
-import traceback
7f5c89
-import getopt
7f5c89
-import sys
7f5c89
-import os
7f5c89
-import errno
7f5c89
+import argparse
7f5c89
+import atexit
7f5c89
 import logging
7f5c89
-import subprocess
7f5c89
+import os
7f5c89
 import shutil
7f5c89
-import shlex
7f5c89
-import pty
7f5c89
-import tty
7f5c89
-import re
7f5c89
-import time
7f5c89
-
7f5c89
-#-------------------------------------------------------------------------------
7f5c89
-
7f5c89
-__all__ = ["config", "setup_certs"]
7f5c89
-
7f5c89
-if __name__ == '__main__':
7f5c89
-    prog_name = os.path.basename(sys.argv[0])
7f5c89
-else:
7f5c89
-    prog_name = 'setup_certs'
7f5c89
-
7f5c89
-serial_number = 0
7f5c89
-hostname = os.uname()[1]
7f5c89
-client_username = 'test_user'
7f5c89
-
7f5c89
-config = {
7f5c89
-    'verbose'          : False,
7f5c89
-    'debug'            : False,
7f5c89
-    'logfile'          : 'setup_certs.log',
7f5c89
-    'log_level'        : logging.WARN,
7f5c89
-    'interactive'      : sys.stdout.isatty(),
7f5c89
-    'dbdir'            : os.path.join(os.path.dirname(sys.argv[0]), 'pki'),
7f5c89
-    'db_passwd'        : 'db_passwd',
7f5c89
-    'noise_file'       : 'noise_file',
7f5c89
-    'ca_subject'       : 'CN=Test CA',
7f5c89
-    'ca_nickname'      : 'test_ca',
7f5c89
-    'server_subject'   : 'CN=%s' % hostname,
7f5c89
-    'server_nickname'  : 'test_server',
7f5c89
-    'client_subject'   : 'CN=%s' % client_username,
7f5c89
-    'client_nickname'  : client_username,
7f5c89
-}
7f5c89
+import subprocess
7f5c89
+import sys
7f5c89
+from string import Template
7f5c89
+import tempfile
7f5c89
 
7f5c89
 #-------------------------------------------------------------------------------
7f5c89
 
7f5c89
 class CmdError(Exception):
7f5c89
-    def __init__(self, cmd, exit_code, msg):
7f5c89
-        self.cmd = cmd
7f5c89
-        self.exit_code = exit_code
7f5c89
-        self.msg = msg
7f5c89
+    def __init__(self, cmd_args, returncode, message=None, stdout=None, stderr=None):
7f5c89
+        self.cmd_args = cmd_args
7f5c89
+        self.returncode = returncode
7f5c89
+        if message is None:
7f5c89
+            self.message = 'Failed error=%s, ' % (returncode)
7f5c89
+            if stderr:
7f5c89
+                self.message += '"%s", ' % stderr
7f5c89
+            self.message += 'args=%s' % (cmd_args)
7f5c89
+        else:
7f5c89
+            self.message = message
7f5c89
+        self.stdout = stdout
7f5c89
+        self.stderr = stderr
7f5c89
 
7f5c89
     def __str__(self):
7f5c89
-        return "Command \"%s\"\nFailed with exit code = %s\nOutput was:\n%s\n" % \
7f5c89
-            (self.cmd, self.exit_code, self.msg)
7f5c89
+        return self.message
7f5c89
 
7f5c89
-#-------------------------------------------------------------------------------
7f5c89
 
7f5c89
-def next_serial():
7f5c89
-    global serial_number
7f5c89
-    serial_number += 1
7f5c89
-    return serial_number
7f5c89
+def run_cmd(cmd_args, input=None):
7f5c89
+    logging.debug(' '.join(cmd_args))
7f5c89
+    try:
7f5c89
+        p = subprocess.Popen(cmd_args,
7f5c89
+                             stdin=subprocess.PIPE,
7f5c89
+                             stdout=subprocess.PIPE,
7f5c89
+                             stderr=subprocess.PIPE)
7f5c89
+        stdout, stderr = p.communicate(input)
7f5c89
+        returncode = p.returncode
7f5c89
+        if returncode != 0:
7f5c89
+            raise CmdError(cmd_args, returncode,
7f5c89
+                           'failed %s' % (', '.join(cmd_args)),
7f5c89
+                           stdout, stderr)
7f5c89
+        return stdout, stderr
7f5c89
+    except OSError as e:
7f5c89
+        raise CmdError(cmd_args, e.errno, stderr=str(e))
7f5c89
+
7f5c89
+def exit_handler(options):
7f5c89
+    logging.debug('in exit handler')
7f5c89
+
7f5c89
+    if options.passwd_filename is not None:
7f5c89
+        logging.debug('removing passwd_filename=%s', options.passwd_filename)
7f5c89
+        os.remove(options.passwd_filename)
7f5c89
+
7f5c89
+    if options.noise_filename is not None:
7f5c89
+        logging.debug('removing noise_filename=%s', options.noise_filename)
7f5c89
+        os.remove(options.noise_filename)
7f5c89
+
7f5c89
+def write_serial(options, serial_number):
7f5c89
+    with open(options.serial_file, 'w') as f:
7f5c89
+        f.write('%x\n' % serial_number)
7f5c89
+
7f5c89
+
7f5c89
+def read_serial(options):
7f5c89
+    if not os.path.exists(options.serial_file):
7f5c89
+        write_serial(options, options.serial_number)
7f5c89
 
7f5c89
-def create_noise_file():
7f5c89
-    """
7f5c89
-    Generate a noise file to be used when creating a key
7f5c89
-    """
7f5c89
-    if os.path.exists(config['noise_file']):
7f5c89
-        os.remove(config['noise_file'])
7f5c89
-
7f5c89
-    f = open(config['noise_file'], "w")
7f5c89
-    f.write(os.urandom(40))
7f5c89
-    f.close()
7f5c89
+    with open(options.serial_file) as f:
7f5c89
+        serial_number = int(f.readline(), 16)
7f5c89
+    return serial_number
7f5c89
 
7f5c89
-    return
7f5c89
 
7f5c89
-def run_cmd(cmd, input=None):
7f5c89
-    logging.debug("running command: %s", cmd)
7f5c89
+def init_noise_file(options):
7f5c89
+    '''Generate a noise file to be used when creating a key
7f5c89
 
7f5c89
-    if input is None:
7f5c89
-        stdin = None
7f5c89
-    else:
7f5c89
-        stdin = subprocess.PIPE
7f5c89
+    We create a temporary file on first use and continue to use
7f5c89
+    the same temporary file for the duration of this process.
7f5c89
+    Each time this function is called it writes new random data
7f5c89
+    into the file.
7f5c89
+    '''
7f5c89
+    random_data = os.urandom(40)
7f5c89
 
7f5c89
-    p = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
7f5c89
-    stdout, stderr = p.communicate(input)
7f5c89
-    status = p.returncode
7f5c89
-    if config['verbose']:
7f5c89
-        logging.debug("cmd status = %s", status)
7f5c89
-        logging.debug("cmd stdout = %s", stdout)
7f5c89
-        logging.debug("cmd stderr = %s", stderr)
7f5c89
-    return status, stdout, stderr
7f5c89
-
7f5c89
-def run_cmd_with_prompts(cmd, prompts):
7f5c89
-    logging.debug('running command: %s', cmd)
7f5c89
-
7f5c89
-    argv = shlex.split(cmd)
7f5c89
-
7f5c89
-    pid, master_fd = pty.fork()
7f5c89
-    if pid == 0:
7f5c89
-        os.execlp(argv[0], *argv)
7f5c89
-
7f5c89
-    time.sleep(0.1)            # FIXME: why is this necessary?
7f5c89
-    output = ''
7f5c89
-    search_position = 0
7f5c89
-    cur_prompt = 0
7f5c89
-    if cur_prompt < len(prompts):
7f5c89
-        prompt_re = re.compile(prompts[cur_prompt][0])
7f5c89
-        response = prompts[cur_prompt][1]
7f5c89
-        cur_prompt += 1
7f5c89
+    if options.noise_filename is None:
7f5c89
+        fd, options.noise_filename = tempfile.mkstemp()
7f5c89
+        os.write(fd, random_data)
7f5c89
+        os.close(fd)
7f5c89
     else:
7f5c89
-        prompt_re = None
7f5c89
-        response = None
7f5c89
-
7f5c89
-    while True:
7f5c89
-        try:
7f5c89
-            new_data = os.read(master_fd, 1024)
7f5c89
-        except OSError, e:
7f5c89
-            if e.errno == errno.EIO: # process exited
7f5c89
-                break
7f5c89
-            else:
7f5c89
-                raise
7f5c89
-        if len(new_data) == 0:
7f5c89
-            break               # EOF
7f5c89
-        output += new_data
7f5c89
-        logging.debug('output="%s"', output[search_position:]);
7f5c89
-        if prompt_re is not None:
7f5c89
-            logging.debug('search pattern = "%s"', prompt_re.pattern)
7f5c89
-            match = prompt_re.search(output, search_position)
7f5c89
-            if match:
7f5c89
-                search_position = match.end()
7f5c89
-                parsed = output[match.start() : match.end()]
7f5c89
-                logging.debug('found prompt: "%s"', parsed)
7f5c89
-                logging.debug('writing response: "%s"', response)
7f5c89
-                os.write(master_fd, response)
7f5c89
-
7f5c89
-                if cur_prompt < len(prompts):
7f5c89
-                    prompt_re = re.compile(prompts[cur_prompt][0])
7f5c89
-                    response = prompts[cur_prompt][1]
7f5c89
-                    cur_prompt += 1
7f5c89
-                else:
7f5c89
-                    prompt_re = None
7f5c89
-                    response = None
7f5c89
-
7f5c89
-
7f5c89
-    exit_value = os.waitpid(pid, 0)[1]
7f5c89
-    exit_signal = exit_value & 0xFF
7f5c89
-    exit_code = exit_value >> 8
7f5c89
-    #logging.debug('output="%s"' % output)
7f5c89
-    logging.debug('cmd signal=%s, exit_code=%s' % (exit_signal, exit_code))
7f5c89
-
7f5c89
-    return exit_code, output
7f5c89
+        with open(options.noise_filename, 'w') as f:
7f5c89
+            f.write(random_data)
7f5c89
+    return
7f5c89
 
7f5c89
+def create_passwd_file(options):
7f5c89
+    fd, options.passwd_filename = tempfile.mkstemp()
7f5c89
+    os.write(fd, options.db_passwd)
7f5c89
+    os.close(fd)
7f5c89
 
7f5c89
-#-------------------------------------------------------------------------------
7f5c89
 
7f5c89
-def setup_certs():
7f5c89
-    print 'setting up certs ...'
7f5c89
-
7f5c89
-    if os.path.exists(config['dbdir']):
7f5c89
-       shutil.rmtree(config['dbdir'])
7f5c89
-    os.makedirs(config['dbdir'])
7f5c89
+def db_has_cert(options, nickname):
7f5c89
+    cmd_args = ['/usr/bin/certutil',
7f5c89
+                '-d', options.db_name,
7f5c89
+                '-L',
7f5c89
+                '-n', nickname]
7f5c89
 
7f5c89
     try:
7f5c89
+        run_cmd(cmd_args)
7f5c89
+    except CmdError as e:
7f5c89
+        if e.returncode == 255 and 'not found' in e.stderr:
7f5c89
+            return False
7f5c89
+        else:
7f5c89
+            raise
7f5c89
+    return True
7f5c89
+
7f5c89
+def format_cert(options, nickname):
7f5c89
+    cmd_args = ['/usr/bin/certutil',
7f5c89
+                '-L',                          # OPERATION: list
7f5c89
+                '-d', options.db_name,         # NSS database
7f5c89
+                '-f', options.passwd_filename, # database password in file
7f5c89
+                '-n', nickname,                # nickname of cert to list
7f5c89
+                ]
7f5c89
 
7f5c89
-        create_noise_file()
7f5c89
-
7f5c89
-        # 1. Create the database
7f5c89
-        cmd = 'certutil -N -d %(dbdir)s' % config
7f5c89
-        exit_code, output = run_cmd_with_prompts(cmd,
7f5c89
-            [('Enter new password:\s*', config['db_passwd'] + '\n'),
7f5c89
-             ('Re-enter password:\s*',  config['db_passwd'] + '\n')])
7f5c89
-        if exit_code != 0:
7f5c89
-            raise CmdError(cmd, exit_code, output)
7f5c89
-
7f5c89
-        # 2. Create a root CA certificate
7f5c89
-        config['serial_number'] = next_serial()
7f5c89
-        cmd = 'certutil -S -d %(dbdir)s -z %(noise_file)s -s "%(ca_subject)s" -n "%(ca_nickname)s" -x -t "CTu,C,C" -m %(serial_number)d' % config
7f5c89
-        exit_code, output = run_cmd_with_prompts(cmd,
7f5c89
-            [('Enter Password or Pin for "NSS Certificate DB":\s*', config['db_passwd'] + '\n')])
7f5c89
-        if exit_code != 0:
7f5c89
-            raise CmdError(cmd, exit_code, output)
7f5c89
-
7f5c89
-        # 3. Create a server certificate and sign it.
7f5c89
-        config['serial_number'] = next_serial()
7f5c89
-        cmd = 'certutil -S -d %(dbdir)s -z %(noise_file)s -c %(ca_nickname)s -s "%(server_subject)s" -n "%(server_nickname)s" -t "u,u,u" -m %(serial_number)d' % config
7f5c89
-        exit_code, output = run_cmd_with_prompts(cmd,
7f5c89
-            [('Enter Password or Pin for "NSS Certificate DB":\s*', config['db_passwd'] + '\n')])
7f5c89
-        if exit_code != 0:
7f5c89
-            raise CmdError(cmd, exit_code, output)
7f5c89
-
7f5c89
-        # 4. Create a client certificate and sign it.
7f5c89
-        config['serial_number'] = next_serial()
7f5c89
-        cmd = 'certutil -S -d %(dbdir)s -z %(noise_file)s -c %(ca_nickname)s -s "%(client_subject)s" -n "%(client_nickname)s" -t "u,u,u" -m %(serial_number)d' % config
7f5c89
-        exit_code, output = run_cmd_with_prompts(cmd,
7f5c89
-                                                 [('Enter Password or Pin for "NSS Certificate DB":\s*', config['db_passwd'] + '\n')])
7f5c89
-        if exit_code != 0:
7f5c89
-            raise CmdError(cmd, exit_code, output)
7f5c89
-
7f5c89
-        # 5. Import public root CA's
7f5c89
-        cmd = 'modutil -dbdir %(dbdir)s -add ca_certs -libfile libnssckbi.so' % config
7f5c89
-        exit_code, stdout, stderr = run_cmd(cmd)
7f5c89
-        if exit_code != 0:
7f5c89
-            raise CmdError(cmd, exit_code, output)
7f5c89
-
7f5c89
-        # 6. Create a sub CA certificate
7f5c89
-        config['serial_number'] = next_serial()
7f5c89
-        config['subca_subject'] = 'CN=subca'
7f5c89
-        config['subca_nickname'] = 'subca'
7f5c89
-        cmd = 'certutil -S -d %(dbdir)s -z %(noise_file)s -c %(ca_nickname)s -s "%(subca_subject)s" -n "%(subca_nickname)s" -t "CTu,C,C" -m %(serial_number)d' % config
7f5c89
-        exit_code, output = run_cmd_with_prompts(cmd,
7f5c89
-            [('Enter Password or Pin for "NSS Certificate DB":\s*', config['db_passwd'] + '\n')])
7f5c89
-        if exit_code != 0:
7f5c89
-            raise CmdError(cmd, exit_code, output)
7f5c89
-
7f5c89
-        # 7. Create a server certificate and sign it with the subca.
7f5c89
-        config['serial_number'] = next_serial()
7f5c89
-        config['server_subject'] = config['server_subject'] + "_" + config['subca_nickname']
7f5c89
-        config['server_nickname'] = config['server_nickname'] + "_" + config['subca_nickname']
7f5c89
-        cmd = 'certutil -S -d %(dbdir)s -z %(noise_file)s -c %(subca_nickname)s -s "%(server_subject)s" -n "%(server_nickname)s" -t "u,u,u" -m %(serial_number)d' % config
7f5c89
-        exit_code, output = run_cmd_with_prompts(cmd,
7f5c89
-            [('Enter Password or Pin for "NSS Certificate DB":\s*', config['db_passwd'] + '\n')])
7f5c89
-        if exit_code != 0:
7f5c89
-            raise CmdError(cmd, exit_code, output)
7f5c89
-
7f5c89
-    finally:
7f5c89
-        if os.path.exists(config['noise_file']):
7f5c89
-            os.remove(config['noise_file'])
7f5c89
-
7f5c89
-    logging.info('certifcate database password="%(db_passwd)s"', config)
7f5c89
-    logging.info('CA nickname="%(ca_nickname)s", CA subject="%(ca_subject)s"', config)
7f5c89
-    logging.info('server nickname="%(server_nickname)s", server subject="%(server_subject)s"', config)
7f5c89
-    logging.info('client nickname="%(client_nickname)s", client subject="%(client_subject)s"', config)
7f5c89
+    stdout, stderr = run_cmd(cmd_args)
7f5c89
+    return stdout
7f5c89
 
7f5c89
 #-------------------------------------------------------------------------------
7f5c89
 
7f5c89
-class Usage(Exception):
7f5c89
-    def __init__(self, msg):
7f5c89
-        self.msg = msg
7f5c89
+def create_database(options):
7f5c89
+    if os.path.exists(options.db_dir) and not os.path.isdir(options.db_dir):
7f5c89
+        raise ValueError('db_dir "%s" exists but is not a directory' % options.db_dir)
7f5c89
+
7f5c89
+    # Create resources
7f5c89
+    create_passwd_file(options)
7f5c89
+
7f5c89
+    if options.clean:
7f5c89
+        logging.info('Creating clean database directory: "%s"', options.db_dir)
7f5c89
+
7f5c89
+        if os.path.exists(options.db_dir):
7f5c89
+            shutil.rmtree(options.db_dir)
7f5c89
+        os.makedirs(options.db_dir)
7f5c89
+
7f5c89
+        cmd_args = ['/usr/bin/certutil',
7f5c89
+                    '-N',                          # OPERATION: create database
7f5c89
+                    '-d', options.db_name,         # NSS database
7f5c89
+                    '-f', options.passwd_filename, # database password in file
7f5c89
+                    ]
7f5c89
 
7f5c89
-def usage():
7f5c89
-    '''
7f5c89
-    Print command help.
7f5c89
-    '''
7f5c89
+        stdout, stderr = run_cmd(cmd_args)
7f5c89
+    else:
7f5c89
+        logging.info('Using existing database directory: "%s"', options.db_dir)
7f5c89
+
7f5c89
+def create_ca_cert(options):
7f5c89
+    serial_number = read_serial(options)
7f5c89
+    init_noise_file(options)
7f5c89
+
7f5c89
+    logging.info('creating ca cert: subject="%s", nickname="%s"',
7f5c89
+                 options.ca_subject, options.ca_nickname)
7f5c89
+
7f5c89
+    cmd_args = ['/usr/bin/certutil',
7f5c89
+                '-S',                            # OPERATION: create signed cert
7f5c89
+                '-x',                            # self-sign the cert
7f5c89
+                '-d', options.db_name,           # NSS database
7f5c89
+                '-f', options.passwd_filename,   # database password in file
7f5c89
+                '-n', options.ca_nickname,       # nickname of cert being created
7f5c89
+                '-s', options.ca_subject,        # subject of cert being created
7f5c89
+                '-g', str(options.key_size),     # keysize
7f5c89
+                '-t', 'CT,,CT',                  # trust
7f5c89
+                '-1',                            # add key usage extension
7f5c89
+                '-2',                            # add basic contraints extension
7f5c89
+                '-5',                            # add certificate type extension
7f5c89
+                '-m', str(serial_number),        # cert serial number
7f5c89
+                '-v', str(options.valid_months), # validity in months
7f5c89
+                '-z', options.noise_filename,    # noise file random seed
7f5c89
+                ]
7f5c89
+
7f5c89
+    # Provide input for extension creation prompting
7f5c89
+    input = ''
7f5c89
+
7f5c89
+    # >> Key Usage extension <<
7f5c89
+    # 0 - Digital Signature
7f5c89
+    # 1 - Non-repudiation
7f5c89
+    # 2 - Key encipherment
7f5c89
+    # 3 - Data encipherment
7f5c89
+    # 4 - Key agreement
7f5c89
+    # 5 - Cert signing key
7f5c89
+    # 6 - CRL signing key
7f5c89
+    # Other to finish
7f5c89
+    input += '0\n1\n5\n100\n'
7f5c89
+    # Is this a critical extension [y/N]?
7f5c89
+    input += 'y\n'
7f5c89
+
7f5c89
+    # >> Basic Constraints extension <<
7f5c89
+    # Is this a CA certificate [y/N]?
7f5c89
+    input += 'y\n'
7f5c89
+    # Enter the path length constraint, enter to skip [<0 for unlimited path]: > 2
7f5c89
+    input += '%d\n' % options.ca_path_len
7f5c89
+    # Is this a critical extension [y/N]?
7f5c89
+    input += 'y\n'
7f5c89
+
7f5c89
+    # >> NS Cert Type extension <<
7f5c89
+    # 0 - SSL Client
7f5c89
+    # 1 - SSL Server
7f5c89
+    # 2 - S/MIME
7f5c89
+    # 3 - Object Signing
7f5c89
+    # 4 - Reserved for future use
7f5c89
+    # 5 - SSL CA
7f5c89
+    # 6 - S/MIME CA
7f5c89
+    # 7 - Object Signing CA
7f5c89
+    # Other to finish
7f5c89
+    input += '5\n6\n7\n100\n'
7f5c89
+    # Is this a critical extension [y/N]?
7f5c89
+    input += 'n\n'
7f5c89
+
7f5c89
+    stdout, stderr = run_cmd(cmd_args, input)
7f5c89
+    write_serial(options, serial_number + 1)
7f5c89
+
7f5c89
+    return options.ca_nickname
7f5c89
+
7f5c89
+def create_server_cert(options):
7f5c89
+    serial_number = read_serial(options)
7f5c89
+    init_noise_file(options)
7f5c89
+
7f5c89
+    logging.info('creating server cert: subject="%s", nickname="%s"',
7f5c89
+                 options.server_subject, options.server_nickname)
7f5c89
+
7f5c89
+    cmd_args = ['/usr/bin/certutil',
7f5c89
+                '-S',                            # OPERATION: create signed cert
7f5c89
+                '-d', options.db_name,           # NSS database
7f5c89
+                '-f', options.passwd_filename,   # database password in file
7f5c89
+                '-c', options.ca_nickname,       # nickname of CA used to sign this cert
7f5c89
+                '-n', options.server_nickname,   # nickname of cert being created
7f5c89
+                '-s', options.server_subject,    # subject of cert being created
7f5c89
+                '-g', str(options.key_size),     # keysize
7f5c89
+                '-t', 'u,u,u',                   # trust
7f5c89
+                '-5',                            # add certificate type extensionn
7f5c89
+                '-m', str(serial_number),        # cert serial number
7f5c89
+                '-v', str(options.valid_months), # validity in months
7f5c89
+                '-z', options.noise_filename,    # noise file random seed
7f5c89
+                ]
7f5c89
+
7f5c89
+    # Provide input for extension creation prompting
7f5c89
+    input = ''
7f5c89
+
7f5c89
+    # >> NS Cert Type extension <<
7f5c89
+    # 0 - SSL Client
7f5c89
+    # 1 - SSL Server
7f5c89
+    # 2 - S/MIME
7f5c89
+    # 3 - Object Signing
7f5c89
+    # 4 - Reserved for future use
7f5c89
+    # 5 - SSL CA
7f5c89
+    # 6 - S/MIME CA
7f5c89
+    # 7 - Object Signing CA
7f5c89
+    # Other to finish
7f5c89
+    input += '1\n100\n'
7f5c89
+    # Is this a critical extension [y/N]?
7f5c89
+    input += 'n\n'
7f5c89
+
7f5c89
+    stdout, stderr = run_cmd(cmd_args, input)
7f5c89
+    write_serial(options, serial_number + 1)
7f5c89
+
7f5c89
+    return options.server_nickname
7f5c89
+
7f5c89
+def create_client_cert(options):
7f5c89
+    serial_number = read_serial(options)
7f5c89
+    init_noise_file(options)
7f5c89
+
7f5c89
+    logging.info('creating client cert: subject="%s", nickname="%s"',
7f5c89
+                 options.client_subject, options.client_nickname)
7f5c89
+
7f5c89
+    cmd_args = ['/usr/bin/certutil',
7f5c89
+                '-S',                            # OPERATION: create signed cert
7f5c89
+                '-d', options.db_name,           # NSS database
7f5c89
+                '-f', options.passwd_filename,   # database password in file
7f5c89
+                '-c', options.ca_nickname,       # nickname of CA used to sign this cert
7f5c89
+                '-n', options.client_nickname,   # nickname of cert being created
7f5c89
+                '-s', options.client_subject,    # subject of cert being created
7f5c89
+                '-g', str(options.key_size),     # keysize
7f5c89
+                '-t', 'u,u,u',                   # trust
7f5c89
+                '-5',                            # add certificate type extensionn
7f5c89
+                '-m', str(serial_number),        # cert serial number
7f5c89
+                '-v', str(options.valid_months), # validity in months
7f5c89
+                '-z', options.noise_filename,    # noise file random seed
7f5c89
+                ]
7f5c89
+
7f5c89
+    # Provide input for extension creation prompting
7f5c89
+    input = ''
7f5c89
+
7f5c89
+    # >> NS Cert Type extension <<
7f5c89
+    # 0 - SSL Client
7f5c89
+    # 1 - SSL Server
7f5c89
+    # 2 - S/MIME
7f5c89
+    # 3 - Object Signing
7f5c89
+    # 4 - Reserved for future use
7f5c89
+    # 5 - SSL CA
7f5c89
+    # 6 - S/MIME CA
7f5c89
+    # 7 - Object Signing CA
7f5c89
+    # Other to finish
7f5c89
+    input += '0\n100\n'
7f5c89
+    # Is this a critical extension [y/N]?
7f5c89
+    input += 'n\n'
7f5c89
+
7f5c89
+    stdout, stderr = run_cmd(cmd_args, input)
7f5c89
+    write_serial(options, serial_number + 1)
7f5c89
+
7f5c89
+    return options.client_nickname
7f5c89
+
7f5c89
+def add_trusted_certs(options):
7f5c89
+    name = 'ca_certs'
7f5c89
+    module = 'libnssckbi.so'
7f5c89
+    logging.info('adding system trusted certs: name="%s" module="%s"',
7f5c89
+                 name, module)
7f5c89
+
7f5c89
+    cmd_args = ['/usr/bin/modutil',
7f5c89
+                '-dbdir', options.db_name, # NSS database
7f5c89
+                '-add', name,              # module name
7f5c89
+                '-libfile', module,        # module
7f5c89
+                ]
7f5c89
 
7f5c89
-    return '''\
7f5c89
--h --help               print help
7f5c89
--l --log-level level    set the logging level, may be one of:
7f5c89
-                        debug, info, warn, error, critical
7f5c89
--L --logfile filename   log to this file, empty string disables logging to a file
7f5c89
--v --verbose            be chatty
7f5c89
--D --debug              show run information
7f5c89
--w --password           set the certificate database password
7f5c89
--d --dbdir              set the datbase directory
7f5c89
--s --server-subject     set the server's subject
7f5c89
-
7f5c89
-Examples:
7f5c89
-
7f5c89
-%(prog_name)s -m 10
7f5c89
-''' % {'prog_name' : prog_name,
7f5c89
-      }
7f5c89
+    run_cmd(cmd_args)
7f5c89
+    return name
7f5c89
 
7f5c89
 #-------------------------------------------------------------------------------
7f5c89
 
7f5c89
-def main(argv=None):
7f5c89
-    if argv is None:
7f5c89
-        argv = sys.argv
7f5c89
+def setup_certs(args):
7f5c89
 
7f5c89
-    try:
7f5c89
-        try:
7f5c89
-            opts, args = getopt.getopt(argv[1:], 'hl:L:vDw:d:s:',
7f5c89
-                                       ['help', 'logfile=', 'verbose', 'debug',
7f5c89
-                                        'password', 'dbdir', 'server-subject'])
7f5c89
-        except getopt.GetoptError, e:
7f5c89
-            raise Usage(e)
7f5c89
-            return 2
7f5c89
-
7f5c89
-        for o, a in opts:
7f5c89
-            if o in ('-h', '--help'):
7f5c89
-                print >>sys.stdout, usage()
7f5c89
-                return 0
7f5c89
-            elif o in ('-L', '--logfile'):
7f5c89
-                if not a:
7f5c89
-                    config['logfile'] = None
7f5c89
-                else:
7f5c89
-                    config['logfile'] = a
7f5c89
-            elif o in ('-l', '--log-level'):
7f5c89
-                if a.upper() in logging._levelNames:
7f5c89
-                    config['log_level'] = logging._levelNames[a.upper()]
7f5c89
-                else:
7f5c89
-                    print >>sys.stderr, "ERROR: unknown log-level '%s'" % a
7f5c89
-            elif o in ('-v', '--verbose'):
7f5c89
-                config['verbose'] = True
7f5c89
-            elif o in ('-D', '--debug'):
7f5c89
-                config['debug'] = True
7f5c89
-            elif o in ('-w', '--password'):
7f5c89
-                config['db_passwd'] = a
7f5c89
-            elif o in ('-d', '--dbdir'):
7f5c89
-                config['dbdir'] = a
7f5c89
-            elif o in ('-s', '--server-subject'):
7f5c89
-                config['server_subject'] = 'CN=%s' % a
7f5c89
-            else:
7f5c89
-                raise Usage("command argument '%s' not handled, internal error" % o)
7f5c89
-    except Usage, e:
7f5c89
-        print >>sys.stderr, e.msg
7f5c89
-        print >>sys.stderr, "for help use --help"
7f5c89
-        return 2
7f5c89
-
7f5c89
-    if config['verbose']:
7f5c89
-        config['log_level'] = logging.INFO
7f5c89
-    if config['debug']:
7f5c89
-        config['log_level'] = logging.DEBUG
7f5c89
+    # --- cmd ---
7f5c89
+    parser = argparse.ArgumentParser(description='create certs for testing',
7f5c89
+                                     formatter_class=argparse.ArgumentDefaultsHelpFormatter)
7f5c89
+
7f5c89
+    parser.add_argument('--verbose', action='store_true',
7f5c89
+                        help='provide info level messages')
7f5c89
+
7f5c89
+    parser.add_argument('--debug', action='store_true',
7f5c89
+                        help='provide debug level messages')
7f5c89
+
7f5c89
+    parser.add_argument('--quiet', action='store_true',
7f5c89
+                        help='do not display any messages')
7f5c89
+
7f5c89
+    parser.add_argument('--show-certs', action='store_true',
7f5c89
+                        help='show the certificate details')
7f5c89
+
7f5c89
+    parser.add_argument('--no-clean', action='store_false', dest='clean',
7f5c89
+                        help='do not remove existing db_dir')
7f5c89
+
7f5c89
+    parser.add_argument('--no-trusted-certs', dest='add_trusted_certs', action='store_false',
7f5c89
+                        help='do not add trusted certs')
7f5c89
+
7f5c89
+    parser.add_argument('--hostname',
7f5c89
+                        help='hostname used in cert subjects')
7f5c89
+
7f5c89
+    parser.add_argument('--db-type',
7f5c89
+                        choices=['sql', ''],
7f5c89
+                        help='NSS database type')
7f5c89
+
7f5c89
+    parser.add_argument('--db-dir',
7f5c89
+                        help='NSS database directory')
7f5c89
+
7f5c89
+    parser.add_argument('--db-passwd',
7f5c89
+                        help='NSS database password')
7f5c89
+
7f5c89
+    parser.add_argument('--ca-subject',
7f5c89
+                        help='CA certificate subject')
7f5c89
+
7f5c89
+    parser.add_argument('--ca-nickname',
7f5c89
+                        help='CA certificate nickname')
7f5c89
+
7f5c89
+    parser.add_argument('--server-subject',
7f5c89
+                        help='server certificate subject')
7f5c89
+
7f5c89
+    parser.add_argument('--server-nickname',
7f5c89
+                        help='server certificate nickname')
7f5c89
+
7f5c89
+    parser.add_argument('--client-username',
7f5c89
+                        help='client user name, used in client cert subject')
7f5c89
+
7f5c89
+    parser.add_argument('--client-subject',
7f5c89
+                        help='client certificate subject')
7f5c89
+
7f5c89
+    parser.add_argument('--client-nickname',
7f5c89
+                        help='client certificate nickname')
7f5c89
+
7f5c89
+    parser.add_argument('--serial-number', type=int,
7f5c89
+                        help='starting serial number for certificates')
7f5c89
+
7f5c89
+    parser.add_argument('--valid-months', dest='valid_months', type=int,
7f5c89
+                        help='validity period in months')
7f5c89
+    parser.add_argument('--path-len', dest='ca_path_len', type=int,
7f5c89
+                        help='basic constraints path length')
7f5c89
+    parser.add_argument('--key-type', dest='key_type',
7f5c89
+                        help='key type, either rsa or dsa')
7f5c89
+    parser.add_argument('--key-size', dest='key_size',
7f5c89
+                        help='number of bits in key (must be multiple of 8)')
7f5c89
+    parser.add_argument('--serial-file', dest='serial_file',
7f5c89
+                        help='name of file used to track next serial number')
7f5c89
+
7f5c89
+    parser.set_defaults(verbose = False,
7f5c89
+                        debug = False,
7f5c89
+                        quiet = False,
7f5c89
+                        show_certs = False,
7f5c89
+                        clean = True,
7f5c89
+                        add_trusted_certs = True,
7f5c89
+                        hostname = os.uname()[1],
7f5c89
+                        db_type = 'sql',
7f5c89
+                        db_dir = 'pki',
7f5c89
+                        db_passwd = 'db_passwd',
7f5c89
+                        ca_subject = 'CN=Test CA',
7f5c89
+                        ca_nickname = 'test_ca',
7f5c89
+                        server_subject =  'CN=${hostname}',
7f5c89
+                        server_nickname = 'test_server',
7f5c89
+                        client_username = 'test_user',
7f5c89
+                        client_subject = 'CN=${client_username}',
7f5c89
+                        client_nickname = '${client_username}',
7f5c89
+                        serial_number = 1,
7f5c89
+                        key_type = 'rsa',
7f5c89
+                        key_size = 1024,
7f5c89
+                        valid_months = 12,
7f5c89
+                        ca_path_len = 2,
7f5c89
+                        serial_file = '${db_dir}/serial',
7f5c89
+                        )
7f5c89
+
7f5c89
+
7f5c89
+    options = parser.parse_args(args)
7f5c89
+
7f5c89
+    # Do substitutions on option values.
7f5c89
+    # This is ugly because argparse does not expose an API which permits iterating over
7f5c89
+    # the contents of options nor a way to get the options as a dict, ugh :-(
7f5c89
+    # So we access options.__dict__ directly.
7f5c89
+    for key in options.__dict__.keys():
7f5c89
+        # Assume options never begin with underscore
7f5c89
+        if key.startswith('_'):
7f5c89
+            continue
7f5c89
+        value = getattr(options, key)
7f5c89
+        # Can't substitue on non-string values
7f5c89
+        if not isinstance(value, basestring):
7f5c89
+            continue
7f5c89
+        # Don't bother trying to substitute if $ substitution character isn't present
7f5c89
+        if '$' not in value:
7f5c89
+            continue
7f5c89
+        setattr(options, key, Template(value).substitute(options.__dict__))
7f5c89
+
7f5c89
+    # Set up logging
7f5c89
+    log_level = logging.INFO
7f5c89
+    if options.quiet:
7f5c89
+        log_level = logging.ERROR
7f5c89
+    if options.verbose:
7f5c89
+        log_level = logging.INFO
7f5c89
+    if options.debug:
7f5c89
+        log_level = logging.DEBUG
7f5c89
 
7f5c89
     # Initialize logging
7f5c89
-    logging.basicConfig(level=config['log_level'],
7f5c89
-                        format='%(asctime)s %(levelname)-8s %(message)s',
7f5c89
-                        datefmt='%m-%d %H:%M',
7f5c89
-                        filename=config['logfile'],
7f5c89
-                        filemode='a')
7f5c89
-
7f5c89
-    if config['interactive']:
7f5c89
-        # Create a seperate logger for the console
7f5c89
-        console_logger = logging.StreamHandler()
7f5c89
-        console_logger.setLevel(config['log_level'])
7f5c89
-        # set a format which is simpler for console use
7f5c89
-        formatter = logging.Formatter('%(message)s')
7f5c89
-        console_logger.setFormatter(formatter)
7f5c89
-        # add the handler to the root logger
7f5c89
-        logging.getLogger('').addHandler(console_logger)
7f5c89
+    logging.basicConfig(level=log_level, format='%(levelname)s: %(message)s')
7f5c89
+    logger = logging.getLogger()
7f5c89
+
7f5c89
+    # Synthesize some useful options derived from specified options
7f5c89
+    if options.db_type == '':
7f5c89
+        options.db_name = options.db_dir
7f5c89
+    else:
7f5c89
+        options.db_name = '%s:%s' % (options.db_type, options.db_dir)
7f5c89
+    options.passwd_filename = None
7f5c89
+    options.noise_filename = None
7f5c89
+
7f5c89
+    # Set function to clean up on exit, bind fuction with options
7f5c89
+    def exit_handler_with_options():
7f5c89
+        exit_handler(options)
7f5c89
+    atexit.register(exit_handler_with_options)
7f5c89
+
7f5c89
+    cert_nicknames = []
7f5c89
 
7f5c89
     try:
7f5c89
-        setup_certs()
7f5c89
-    except Exception, e:
7f5c89
-        logging.error(traceback.format_exc())
7f5c89
-        logging.error(str(e))
7f5c89
+        create_database(options)
7f5c89
+        cert_nicknames.append(create_ca_cert(options))
7f5c89
+        cert_nicknames.append(create_server_cert(options))
7f5c89
+        cert_nicknames.append(create_client_cert(options))
7f5c89
+        if options.add_trusted_certs:
7f5c89
+            add_trusted_certs(options)
7f5c89
+    except CmdError as e:
7f5c89
+        logging.error(e.message)
7f5c89
+        logging.error(e.stderr)
7f5c89
         return 1
7f5c89
 
7f5c89
+    if options.show_certs:
7f5c89
+        if logger.getEffectiveLevel() > logging.INFO:
7f5c89
+            logger.setLevel(logging.INFO)
7f5c89
+        for nickname in cert_nicknames:
7f5c89
+            logging.info('Certificate nickname "%s"\n%s',
7f5c89
+                         nickname, format_cert(options, nickname))
7f5c89
+
7f5c89
+    logging.info('---------- Summary ----------')
7f5c89
+    logging.info('NSS database name="%s", password="%s"',
7f5c89
+                 options.db_name, options.db_passwd)
7f5c89
+    logging.info('CA nickname="%s", CA subject="%s"',
7f5c89
+                 options.ca_nickname, options.ca_subject)
7f5c89
+    logging.info('server nickname="%s", server subject="%s"',
7f5c89
+                 options.server_nickname, options.server_subject)
7f5c89
+    logging.info('client nickname="%s", client subject="%s"',
7f5c89
+                 options.client_nickname, options.client_subject)
7f5c89
+
7f5c89
     return 0
7f5c89
 
7f5c89
 #-------------------------------------------------------------------------------
7f5c89
 
7f5c89
+def main():
7f5c89
+    return setup_certs(None)
7f5c89
+
7f5c89
 if __name__ == '__main__':
7f5c89
     sys.exit(main())
7f5c89
diff -N -u -r python-nss-0.14.0/test/test_client_server.py python-nss-0.14.1/test/test_client_server.py
7f5c89
--- python-nss-0.14.0/test/test_client_server.py	2013-04-30 13:00:23.000000000 -0400
7f5c89
+++ python-nss-0.14.1/test/test_client_server.py	2013-10-08 09:35:53.000000000 -0400
7f5c89
@@ -25,13 +25,12 @@
7f5c89
 password = 'db_passwd'
7f5c89
 use_ssl = True
7f5c89
 client_cert_action = NO_CLIENT_CERT
7f5c89
-certdir = os.path.join(os.path.dirname(sys.argv[0]), 'pki')
7f5c89
+db_name = 'sql:pki'
7f5c89
 hostname = os.uname()[1]
7f5c89
 server_nickname = 'test_server'
7f5c89
 client_nickname = 'test_user'
7f5c89
 port = 1234
7f5c89
 timeout_secs = 10
7f5c89
-family = io.PR_AF_INET
7f5c89
 sleep_time = 5
7f5c89
 
7f5c89
 
7f5c89
@@ -142,7 +141,6 @@
7f5c89
         if info: print "client: using SSL"
7f5c89
         ssl.set_domestic_policy()
7f5c89
 
7f5c89
-    valid_addr = False
7f5c89
     # Get the IP Address of our server
7f5c89
     try:
7f5c89
         addr_info = io.AddrInfo(hostname)
7f5c89
@@ -151,8 +149,6 @@
7f5c89
         return
7f5c89
 
7f5c89
     for net_addr in addr_info:
7f5c89
-        if family != io.PR_AF_UNSPEC:
7f5c89
-            if net_addr.family != family: continue
7f5c89
         net_addr.port = port
7f5c89
 
7f5c89
         if use_ssl:
7f5c89
@@ -180,26 +176,21 @@
7f5c89
             if verbose: print "client trying connection to: %s" % (net_addr)
7f5c89
             sock.connect(net_addr, timeout=io.seconds_to_interval(timeout_secs))
7f5c89
             if verbose: print "client connected to: %s" % (net_addr)
7f5c89
-            valid_addr = True
7f5c89
             break
7f5c89
         except Exception, e:
7f5c89
             sock.close()
7f5c89
             print >>sys.stderr, "client: connection to: %s failed (%s)" % (net_addr, e)
7f5c89
 
7f5c89
-    if not valid_addr:
7f5c89
-        print >>sys.stderr, "Could not establish valid address for \"%s\" in family %s" % \
7f5c89
-        (hostname, io.addr_family_name(family))
7f5c89
-        return
7f5c89
-
7f5c89
     # Talk to the server
7f5c89
     try:
7f5c89
         if info: print "client: sending \"%s\"" % (request)
7f5c89
-        sock.send(request)
7f5c89
-        buf = sock.recv(1024)
7f5c89
+        sock.send(request + '\n') # newline is protocol record separator
7f5c89
+        buf = sock.readline()
7f5c89
         if not buf:
7f5c89
             print >>sys.stderr, "client: lost connection"
7f5c89
             sock.close()
7f5c89
             return
7f5c89
+        buf = buf.rstrip()        # remove newline record separator
7f5c89
         if info: print "client: received \"%s\"" % (buf)
7f5c89
     except Exception, e:
7f5c89
         print >>sys.stderr, "client: %s" % e
7f5c89
@@ -228,15 +219,11 @@
7f5c89
 # -----------------------------------------------------------------------------
7f5c89
 
7f5c89
 def server():
7f5c89
-    global family
7f5c89
-
7f5c89
     if verbose: print "starting server:"
7f5c89
 
7f5c89
     # Initialize
7f5c89
     # Setup an IP Address to listen on any of our interfaces
7f5c89
-    if family == io.PR_AF_UNSPEC:
7f5c89
-        family = io.PR_AF_INET
7f5c89
-    net_addr = io.NetworkAddress(io.PR_IpAddrAny, port, family)
7f5c89
+    net_addr = io.NetworkAddress(io.PR_IpAddrAny, port)
7f5c89
 
7f5c89
     if use_ssl:
7f5c89
         if info: print "server: using SSL"
7f5c89
@@ -290,15 +277,16 @@
7f5c89
         while True:
7f5c89
             try:
7f5c89
                 # Handle the client connection
7f5c89
-                buf = client_sock.recv(1024)
7f5c89
+                buf = client_sock.readline()   # newline is protocol record separator
7f5c89
                 if not buf:
7f5c89
                     print >>sys.stderr, "server: lost lost connection to %s" % (client_addr)
7f5c89
                     break
7f5c89
+                buf = buf.rstrip()             # remove newline record separator
7f5c89
 
7f5c89
                 if info: print "server: received \"%s\"" % (buf)
7f5c89
-                reply = "{%s}" % buf # echo
7f5c89
+                reply = "{%s}" % buf           # echo embedded inside braces
7f5c89
                 if info: print "server: sending \"%s\"" % (reply)
7f5c89
-                client_sock.send(reply) # echo
7f5c89
+                client_sock.send(reply + '\n') # send echo with record separator
7f5c89
 
7f5c89
                 time.sleep(sleep_time)
7f5c89
                 client_sock.shutdown()
7f5c89
@@ -320,7 +308,7 @@
7f5c89
 def run_server():
7f5c89
     pid = os.fork()
7f5c89
     if pid == 0:
7f5c89
-        nss.nss_init(certdir)
7f5c89
+        nss.nss_init(db_name)
7f5c89
         server()
7f5c89
         nss.nss_shutdown()
7f5c89
     time.sleep(sleep_time)
7f5c89
@@ -348,7 +336,7 @@
7f5c89
 
7f5c89
     def test_ssl(self):
7f5c89
         request = "foo"
7f5c89
-        nss.nss_init(certdir)
7f5c89
+        nss.nss_init(db_name)
7f5c89
         reply = client(request)
7f5c89
         nss.nss_shutdown()
7f5c89
         self.assertEqual("{%s}" % request, reply)
7f5c89
diff -N -u -r python-nss-0.14.0/test/test_ocsp.py python-nss-0.14.1/test/test_ocsp.py
7f5c89
--- python-nss-0.14.0/test/test_ocsp.py	2013-04-24 12:36:07.000000000 -0400
7f5c89
+++ python-nss-0.14.1/test/test_ocsp.py	2013-10-08 09:09:18.000000000 -0400
7f5c89
@@ -7,7 +7,7 @@
7f5c89
 import nss.nss as nss
7f5c89
 from nss.error import NSPRError
7f5c89
 
7f5c89
-certdir = 'pki'
7f5c89
+db_name = 'sql:pki'
7f5c89
 
7f5c89
 #-------------------------------------------------------------------------------
7f5c89
 
7f5c89
@@ -16,7 +16,7 @@
7f5c89
 
7f5c89
 class TestAPI(unittest.TestCase):
7f5c89
     def setUp(self):
7f5c89
-        nss.nss_init_read_write(certdir)
7f5c89
+        nss.nss_init_read_write(db_name)
7f5c89
         self.certdb = nss.get_default_certdb()
7f5c89
 
7f5c89
     def tearDown(self):
7f5c89
diff -N -u -r python-nss-0.14.0/test/test_pkcs12.py python-nss-0.14.1/test/test_pkcs12.py
7f5c89
--- python-nss-0.14.0/test/test_pkcs12.py	2013-04-15 13:05:46.000000000 -0400
7f5c89
+++ python-nss-0.14.1/test/test_pkcs12.py	2013-10-17 10:29:09.000000000 -0400
7f5c89
@@ -2,6 +2,7 @@
7f5c89
 
7f5c89
 import sys
7f5c89
 import os
7f5c89
+import re
7f5c89
 import subprocess
7f5c89
 import shlex
7f5c89
 import unittest
7f5c89
@@ -13,30 +14,55 @@
7f5c89
 #-------------------------------------------------------------------------------
7f5c89
 
7f5c89
 verbose = False
7f5c89
-certdir = 'pki'
7f5c89
+db_name = 'sql:pki'
7f5c89
 db_passwd = 'db_passwd'
7f5c89
-pkcs12_file_password = 'pk12_passwd'
7f5c89
+pk12_passwd = 'pk12_passwd'
7f5c89
 
7f5c89
-read_nickname = 'test_user'
7f5c89
-read_pkcs12_file = '%s.p12' % read_nickname
7f5c89
-
7f5c89
-write_export_file = False
7f5c89
-export_nickname = 'test_server'
7f5c89
+cert_nickname = 'test_user'
7f5c89
+pk12_filename = '%s.p12' % cert_nickname
7f5c89
+exported_pk12_filename = 'exported_%s' % pk12_filename
7f5c89
 
7f5c89
 #-------------------------------------------------------------------------------
7f5c89
 
7f5c89
-def run_cmd(cmd):
7f5c89
-    if verbose: print "running command: %s" % cmd
7f5c89
-
7f5c89
-    args = shlex.split(cmd)
7f5c89
-    subprocess.check_call(args, stdout=subprocess.PIPE)
7f5c89
+class CmdError(Exception):
7f5c89
+    def __init__(self, cmd_args, returncode, message=None, stdout=None, stderr=None):
7f5c89
+        self.cmd_args = cmd_args
7f5c89
+        self.returncode = returncode
7f5c89
+        if message is None:
7f5c89
+            self.message = 'Failed error=%s, ' % (returncode)
7f5c89
+            if stderr:
7f5c89
+                self.message += '"%s", ' % stderr
7f5c89
+            self.message += 'args=%s' % (cmd_args)
7f5c89
+        else:
7f5c89
+            self.message = message
7f5c89
+        self.stdout = stdout
7f5c89
+        self.stderr = stderr
7f5c89
+
7f5c89
+    def __str__(self):
7f5c89
+        return self.message
7f5c89
+
7f5c89
+
7f5c89
+def run_cmd(cmd_args, input=None):
7f5c89
+    try:
7f5c89
+        p = subprocess.Popen(cmd_args,
7f5c89
+                             stdin=subprocess.PIPE,
7f5c89
+                             stdout=subprocess.PIPE,
7f5c89
+                             stderr=subprocess.PIPE)
7f5c89
+        stdout, stderr = p.communicate(input)
7f5c89
+        returncode = p.returncode
7f5c89
+        if returncode != 0:
7f5c89
+            raise CmdError(cmd_args, returncode,
7f5c89
+                           'failed %s' % (', '.join(cmd_args)),
7f5c89
+                           stdout, stderr)
7f5c89
+        return stdout, stderr
7f5c89
+    except OSError as e:
7f5c89
+        raise CmdError(cmd_args, e.errno, stderr=str(e))
7f5c89
 
7f5c89
 #-------------------------------------------------------------------------------
7f5c89
 
7f5c89
 def password_callback(slot, retry):
7f5c89
     return db_passwd
7f5c89
 
7f5c89
-#-------------------------------------------------------------------------------
7f5c89
 
7f5c89
 def nickname_collision_callback(old_nickname, cert):
7f5c89
     cancel = False
7f5c89
@@ -44,6 +70,51 @@
7f5c89
     return new_nickname, cancel
7f5c89
 
7f5c89
 
7f5c89
+def get_cert_der_from_db(nickname):
7f5c89
+    cmd_args = ['/usr/bin/certutil',
7f5c89
+                '-d', db_name,
7f5c89
+                '-L',
7f5c89
+                '-n', nickname]
7f5c89
+
7f5c89
+    try:
7f5c89
+        stdout, stderr = run_cmd(cmd_args)
7f5c89
+    except CmdError as e:
7f5c89
+        if e.returncode == 255 and 'not found' in e.stderr:
7f5c89
+            return None
7f5c89
+        else:
7f5c89
+            raise
7f5c89
+    return stdout
7f5c89
+
7f5c89
+def delete_cert_from_db(nickname):
7f5c89
+    cmd_args = ['/usr/bin/certutil',
7f5c89
+                '-d', db_name,
7f5c89
+                '-D',
7f5c89
+                '-n', nickname]
7f5c89
+
7f5c89
+    run_cmd(cmd_args)
7f5c89
+
7f5c89
+def create_pk12(nickname, filename):
7f5c89
+    cmd_args = ['/usr/bin/pk12util',
7f5c89
+                '-o', filename,
7f5c89
+                '-n', nickname,
7f5c89
+                '-d', db_name,
7f5c89
+                '-K', db_passwd,
7f5c89
+                '-W', pk12_passwd]
7f5c89
+    run_cmd(cmd_args)
7f5c89
+
7f5c89
+def list_pk12(filename):
7f5c89
+    cmd_args = ['/usr/bin/pk12util',
7f5c89
+                '-l', filename,
7f5c89
+                '-W', pk12_passwd]
7f5c89
+    stdout, stderr = run_cmd(cmd_args)
7f5c89
+    return stdout
7f5c89
+
7f5c89
+def strip_key_from_pk12_listing(text):
7f5c89
+    match = re.search(r'^Certificate:$', text, re.MULTILINE)
7f5c89
+    if not match:
7f5c89
+        raise ValueError('Could not file Key section in pk12 listing')
7f5c89
+    return text[match.start(0):]
7f5c89
+
7f5c89
 #-------------------------------------------------------------------------------
7f5c89
 
7f5c89
 def load_tests(loader, tests, pattern):
7f5c89
@@ -59,22 +130,23 @@
7f5c89
 
7f5c89
 class TestPKCS12Decoder(unittest.TestCase):
7f5c89
     def setUp(self):
7f5c89
-        nss.nss_init_read_write(certdir)
7f5c89
+        nss.nss_init_read_write(db_name)
7f5c89
         nss.set_password_callback(password_callback)
7f5c89
         nss.pkcs12_set_nickname_collision_callback(nickname_collision_callback)
7f5c89
         nss.pkcs12_enable_all_ciphers()
7f5c89
+        self.cert_der = get_cert_der_from_db(cert_nickname)
7f5c89
+        if self.cert_der is None:
7f5c89
+            raise ValueError('cert with nickname "%s" not in database "%s"' % (cert_nickname, db_name))
7f5c89
 
7f5c89
     def tearDown(self):
7f5c89
         nss.nss_shutdown()
7f5c89
 
7f5c89
     def test_read(self):
7f5c89
         if verbose: print "test_read"
7f5c89
-        cmd='pk12util -o %s -n %s -d pki -K %s -W %s' % \
7f5c89
-            (read_pkcs12_file, read_nickname, db_passwd, pkcs12_file_password)
7f5c89
-        run_cmd(cmd)
7f5c89
+        create_pk12(cert_nickname, pk12_filename)
7f5c89
 
7f5c89
         slot = nss.get_internal_key_slot()
7f5c89
-        pkcs12 = nss.PKCS12Decoder(read_pkcs12_file, pkcs12_file_password, slot)
7f5c89
+        pkcs12 = nss.PKCS12Decoder(pk12_filename, pk12_passwd, slot)
7f5c89
 
7f5c89
         self.assertEqual(len(pkcs12), 3)
7f5c89
         cert_bag_count = 0
7f5c89
@@ -102,33 +174,43 @@
7f5c89
 
7f5c89
     def test_import(self):
7f5c89
         if verbose: print "test_import"
7f5c89
-        cmd='certutil -d pki -D -n %s' % (read_nickname)
7f5c89
-        run_cmd(cmd)
7f5c89
+        delete_cert_from_db(cert_nickname)
7f5c89
+        self.assertEqual(get_cert_der_from_db(cert_nickname), None)
7f5c89
 
7f5c89
         slot = nss.get_internal_key_slot()
7f5c89
-        pkcs12 = nss.PKCS12Decoder(read_pkcs12_file, pkcs12_file_password, slot)
7f5c89
+        pkcs12 = nss.PKCS12Decoder(pk12_filename, pk12_passwd, slot)
7f5c89
         slot.authenticate()
7f5c89
         pkcs12.database_import()
7f5c89
+        cert_der = get_cert_der_from_db(cert_nickname)
7f5c89
+        self.assertEqual(cert_der, self.cert_der)
7f5c89
 
7f5c89
 #-------------------------------------------------------------------------------
7f5c89
 
7f5c89
 class TestPKCS12Export(unittest.TestCase):
7f5c89
     def setUp(self):
7f5c89
-        nss.nss_init(certdir)
7f5c89
+        nss.nss_init(db_name)
7f5c89
         nss.set_password_callback(password_callback)
7f5c89
         nss.pkcs12_enable_all_ciphers()
7f5c89
+        self.cert_der = get_cert_der_from_db(cert_nickname)
7f5c89
+        if self.cert_der is None:
7f5c89
+            raise ValueError('cert with nickname "%s" not in database "%s"' % (cert_nickname, db_name))
7f5c89
 
7f5c89
     def tearDown(self):
7f5c89
         nss.nss_shutdown()
7f5c89
 
7f5c89
     def test_export(self):
7f5c89
         if verbose: print "test_export"
7f5c89
-        pkcs12_data = nss.pkcs12_export(export_nickname, pkcs12_file_password)
7f5c89
-        if write_export_file:
7f5c89
-            p12_file_path = os.path.join(os.path.dirname(sys.argv[0]), "%s.p12" % export_nickname)
7f5c89
-            f = open(p12_file_path, 'w')
7f5c89
+        pkcs12_data = nss.pkcs12_export(cert_nickname, pk12_passwd)
7f5c89
+        with open(exported_pk12_filename, 'w') as f:
7f5c89
             f.write(pkcs12_data)
7f5c89
-            f.close()
7f5c89
+
7f5c89
+        pk12_listing = list_pk12(pk12_filename)
7f5c89
+        pk12_listing = strip_key_from_pk12_listing(pk12_listing)
7f5c89
+
7f5c89
+        exported_pk12_listing = list_pk12(exported_pk12_filename)
7f5c89
+        exported_pk12_listing = strip_key_from_pk12_listing(exported_pk12_listing)
7f5c89
+
7f5c89
+        self.assertEqual(pk12_listing, exported_pk12_listing)
7f5c89
 
7f5c89
 if __name__ == '__main__':
7f5c89
     unittest.main()
7f5c89
diff -N -u -r python-nss-0.14.0/test/util.py python-nss-0.14.1/test/util.py
7f5c89
--- python-nss-0.14.0/test/util.py	1969-12-31 19:00:00.000000000 -0500
7f5c89
+++ python-nss-0.14.1/test/util.py	2013-06-13 09:58:32.000000000 -0400
7f5c89
@@ -0,0 +1,40 @@
7f5c89
+import sys
7f5c89
+import os
7f5c89
+from distutils.util import get_platform
7f5c89
+
7f5c89
+def get_build_dir():
7f5c89
+    '''
7f5c89
+    Walk from the current directory up until a directory is found
7f5c89
+    which contains a regular file called "setup.py" and a directory
7f5c89
+    called "build". If found return the fully qualified path to
7f5c89
+    the build directory's platform specific directory, this is where
7f5c89
+    the architecture specific build produced by setup.py is located.
7f5c89
+
7f5c89
+    There is no API in distutils to return the platform specific
7f5c89
+    directory so we use as much as distutils exposes, the rest was
7f5c89
+    determined by looking at the source code for distutils.
7f5c89
+
7f5c89
+    If the build directory cannont be found in the tree None is returned.
7f5c89
+    '''
7f5c89
+    cwd = os.getcwd()
7f5c89
+    path_components = cwd.split('/')
7f5c89
+    while (len(path_components)):
7f5c89
+        path = os.path.join('/', *path_components)
7f5c89
+        setup_path = os.path.join(path, 'setup.py')
7f5c89
+        build_path = os.path.join(path, 'build')
7f5c89
+        # Does this directory contain the file "setup.py" and the directory "build"?
7f5c89
+        if os.path.exists(setup_path) and os.path.exists(build_path) and \
7f5c89
+           os.path.isfile(setup_path) and os.path.isdir(build_path):
7f5c89
+            # Found, return the path contentated with the architecture
7f5c89
+            # specific build directory
7f5c89
+            platform_specifier = "lib.%s-%s" % (get_platform(), sys.version[0:3])
7f5c89
+            return os.path.join(build_path, platform_specifier)
7f5c89
+
7f5c89
+        # Not found, ascend to parent directory and try again
7f5c89
+        path_components.pop()
7f5c89
+
7f5c89
+    # Failed to find the build directory
7f5c89
+    return None
7f5c89
+
7f5c89
+def insert_build_dir_into_path():
7f5c89
+    sys.path.insert(0,get_build_dir())