From 484eff1016ab00cc7c3c3dc4be3fb0fd7179a994 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Wed, 1 Apr 2009 22:39:44 -0400 Subject: Implement an installer for the Dogtag certificate system. The CA is currently not automatically installed. You have to pass in the --ca flag to install it. What works: - installation - unistallation - cert/ra plugins can issue and retrieve server certs What doesn't work: - self-signed CA is still created and issues Apache and DS certs - dogtag and python-nss not in rpm requires - requires that CS be in the "pre" install state from pkicreate --- ipapython/nsslib.py | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 ipapython/nsslib.py (limited to 'ipapython') diff --git a/ipapython/nsslib.py b/ipapython/nsslib.py new file mode 100644 index 000000000..fd27028e7 --- /dev/null +++ b/ipapython/nsslib.py @@ -0,0 +1,150 @@ +# Authors: Rob Crittenden +# +# Copyright (C) 2009 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; version 2 only +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +import httplib +import getpass +import socket +import errno + +from nss.error import NSPRError +import nss.io as io +import nss.nss as nss +import nss.ssl as ssl + +def client_auth_data_callback(ca_names, chosen_nickname, password, certdb): + cert = None + if chosen_nickname: + try: + cert = nss.find_cert_from_nickname(chosen_nickname, password) + priv_key = nss.find_key_by_any_cert(cert, password) + return cert, priv_key + except NSPRError: + return False + else: + nicknames = nss.get_cert_nicknames(certdb, nss.SEC_CERT_NICKNAMES_USER) + for nickname in nicknames: + try: + cert = nss.find_cert_from_nickname(nickname, password) + if cert.check_valid_times(): + if cert.has_signer_in_ca_names(ca_names): + priv_key = nss.find_key_by_any_cert(cert, password) + return cert, priv_key + except NSPRError: + return False + return False + +class SSLFile(httplib.SSLFile): + """ + Override the _read method so we can use the NSS recv method. + """ + def _read(self): + buf = '' + while True: + try: + buf = self._ssl.recv(self._bufsize) + except NSPRError, e: + raise e + else: + break + return buf + +class NSSFakeSocket(httplib.FakeSocket): + def makefile(self, mode, bufsize=None): + if mode != 'r' and mode != 'rb': + raise httplib.UnimplementedFileMode() + return SSLFile(self._shared, self._ssl, bufsize) + + def send(self, stuff, flags = 0): + return self._ssl.send(stuff) + + sendall = send + +class NSSConnection(httplib.HTTPConnection): + default_port = httplib.HTTPSConnection.default_port + + def __init__(self, host, port=None, key_file=None, cert_file=None, + ca_file='/etc/pki/tls/certs/ca-bundle.crt', strict=None, + dbdir=None): + httplib.HTTPConnection.__init__(self, host, port, strict) + self.key_file = key_file + self.cert_file = cert_file + self.ca_file = ca_file + + if not dbdir: + raise RuntimeError("dbdir is required") + + ssl.nssinit(dbdir) + ssl.set_domestic_policy() + nss.set_password_callback(self.password_callback) + + # Create the socket here so we can do things like let the caller + # override the NSS callbacks + self.sslsock = ssl.SSLSocket() + self.sslsock.set_ssl_option(ssl.SSL_SECURITY, True) + self.sslsock.set_ssl_option(ssl.SSL_HANDSHAKE_AS_CLIENT, True) + self.sslsock.set_handshake_callback(self.handshake_callback) + + def password_callback(self, slot, retry, password): + if not retry and password: return password + return getpass.getpass("Enter password for %s: " % slot.token_name); + + def handshake_callback(self, sock): + """ + Verify callback. If we get here then the certificate is ok. + """ + if self.debuglevel > 0: + print "handshake complete, peer = %s" % (sock.get_peer_name()) + pass + + def connect(self): + self.sslsock.set_hostname(self.host) + + net_addr = io.NetworkAddress(self.host, self.port) + + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.sslsock.connect(net_addr) + self.sock = NSSFakeSocket(sock, self.sslsock) + +class NSSHTTPS(httplib.HTTP): + _connection_class = NSSConnection + + def __init__(self, host='', port=None, key_file=None, cert_file=None, + ca_file='/etc/pki/tls/certs/ca-bundle.crt', strict=None): + # provide a default host, pass the X509 cert info + + # urf. compensate for bad input. + if port == 0: + port = None + self._setup(self._connection_class(host, port, key_file, + cert_file, ca_file, strict)) + # we never actually use these for anything, but we keep them + # here for compatibility with post-1.5.2 CVS. + self.key_file = key_file + self.cert_file = cert_file + self.ca_file = ca_file + +if __name__ == "__main__": + h = NSSConnection("www.verisign.com", 443, dbdir="/etc/pki/nssdb") + h.set_debuglevel(1) + h.request("GET", "/") + res = h.getresponse() + print res.status + data = res.read() + print data + h.close() -- cgit