diff options
author | Rob Crittenden <rcritten@redhat.com> | 2009-04-01 22:39:44 -0400 |
---|---|---|
committer | Rob Crittenden <rcritten@redhat.com> | 2009-04-03 14:06:09 -0400 |
commit | 484eff1016ab00cc7c3c3dc4be3fb0fd7179a994 (patch) | |
tree | 65965f10a2f4b1650bbef5de667a6f6d1a882c42 /ipapython/nsslib.py | |
parent | a6294ba041aa4568b414b5f25a345c00a031667e (diff) | |
download | freeipa-484eff1016ab00cc7c3c3dc4be3fb0fd7179a994.tar.gz freeipa-484eff1016ab00cc7c3c3dc4be3fb0fd7179a994.tar.xz freeipa-484eff1016ab00cc7c3c3dc4be3fb0fd7179a994.zip |
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
Diffstat (limited to 'ipapython/nsslib.py')
-rw-r--r-- | ipapython/nsslib.py | 150 |
1 files changed, 150 insertions, 0 deletions
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 <rcritten@redhat.com> +# +# 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() |