mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
use NSS for SSL operations
This commit is contained in:
committed by
Rob Crittenden
parent
1dd7b11b0b
commit
31027c6183
@@ -178,7 +178,7 @@ Requires: python-kerberos >= 1.1-3
|
||||
Requires: authconfig
|
||||
Requires: gnupg
|
||||
Requires: pyOpenSSL
|
||||
Requires: python-nss >= 0.8
|
||||
Requires: python-nss >= 0.9
|
||||
Requires: python-lxml
|
||||
|
||||
%description python
|
||||
|
||||
133
ipalib/rpc.py
133
ipalib/rpc.py
@@ -32,7 +32,6 @@ Also see the `ipaserver.rpcserver` module.
|
||||
|
||||
from types import NoneType
|
||||
import threading
|
||||
import socket
|
||||
import os
|
||||
import errno
|
||||
from xmlrpclib import Binary, Fault, dumps, loads, ServerProxy, Transport, ProtocolError
|
||||
@@ -42,15 +41,9 @@ from ipalib.errors import public_errors, PublicError, UnknownError, NetworkError
|
||||
from ipalib import errors
|
||||
from ipalib.request import context
|
||||
from ipapython import ipautil
|
||||
from OpenSSL import SSL
|
||||
import httplib
|
||||
|
||||
try:
|
||||
from httplib import SSLFile
|
||||
from httplib import FakeSocket
|
||||
except ImportError:
|
||||
from ipapython.ipasslfile import SSLFile
|
||||
from ipapython.ipasslfile import FakeSocket
|
||||
from ipapython.nsslib import NSSHTTPS
|
||||
from nss.error import NSPRError
|
||||
|
||||
# Some Kerberos error definitions from krb5.h
|
||||
KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN = (-1765328377L)
|
||||
@@ -199,121 +192,9 @@ class SSLTransport(Transport):
|
||||
|
||||
def make_connection(self, host):
|
||||
host, extra_headers, x509 = self.get_host_info(host)
|
||||
return SSLSocket(host, None, **(x509 or {}))
|
||||
|
||||
|
||||
class SSLFile(SSLFile):
|
||||
"""
|
||||
Override the _read method so we can handle PyOpenSSL errors
|
||||
gracefully.
|
||||
"""
|
||||
def _read(self):
|
||||
buf = ''
|
||||
while True:
|
||||
try:
|
||||
buf = self._ssl.read(self._bufsize)
|
||||
except SSL.ZeroReturnError:
|
||||
# Nothing more to be read
|
||||
break
|
||||
except SSL.SysCallError, e:
|
||||
print "SSL exception", e.args
|
||||
break
|
||||
except SSL.WantWriteError:
|
||||
break
|
||||
except SSL.WantReadError:
|
||||
break
|
||||
except socket.error, err:
|
||||
if err[0] == errno.EINTR:
|
||||
continue
|
||||
if err[0] == errno.EBADF:
|
||||
# XXX socket was closed?
|
||||
break
|
||||
raise
|
||||
else:
|
||||
break
|
||||
return buf
|
||||
|
||||
|
||||
class FakeSocket(FakeSocket):
|
||||
"""
|
||||
Override this class so we can end up using our own SSLFile
|
||||
implementation.
|
||||
"""
|
||||
def makefile(self, mode, bufsize=None):
|
||||
if mode != 'r' and mode != 'rb':
|
||||
raise httplib.UnimplementedFileMode()
|
||||
return SSLFile(self._shared, self._ssl, bufsize)
|
||||
|
||||
|
||||
class SSLConnection(httplib.HTTPConnection):
|
||||
"""
|
||||
Use OpenSSL as the SSL provider instead of the built-in python SSL
|
||||
support. The built-in SSL client doesn't do CA validation.
|
||||
|
||||
By default we will attempt to load the ca-bundle.crt and our own
|
||||
IPA CA for validation purposes. To add an additional CA to verify
|
||||
against set the x509['ca_file'] to the path of the CA PEM file in
|
||||
KerbTransport.get_host_info
|
||||
"""
|
||||
default_port = httplib.HTTPSConnection.default_port
|
||||
|
||||
def verify_callback(self, conn, cert, errnum, depth, ok):
|
||||
"""
|
||||
Verify callback. If we get here then the certificate is ok.
|
||||
"""
|
||||
return ok
|
||||
|
||||
def __init__(self, host, port=None, key_file=None, cert_file=None,
|
||||
ca_file=None, strict=None):
|
||||
httplib.HTTPConnection.__init__(self, host, port, strict)
|
||||
self.key_file = key_file
|
||||
self.cert_file = cert_file
|
||||
self.ca_file = ca_file
|
||||
|
||||
def connect(self):
|
||||
ctx = SSL.Context(SSL.SSLv23_METHOD)
|
||||
ctx.set_verify(SSL.VERIFY_PEER, self.verify_callback)
|
||||
if self.key_file:
|
||||
ctx.use_privatekey_file (self.key_file)
|
||||
if self.cert_file:
|
||||
ctx.use_certificate_file(self.cert_file)
|
||||
if os.path.exists("/etc/pki/tls/certs/ca-bundle.crt"):
|
||||
ctx.load_verify_locations("/etc/pki/tls/certs/ca-bundle.crt")
|
||||
if os.path.exists("/etc/ipa/ca.crt"):
|
||||
ctx.load_verify_locations("/etc/ipa/ca.crt")
|
||||
if self.ca_file is not None and os.path.exists(self.ca_file):
|
||||
ctx.load_verify_locations(self.ca_file)
|
||||
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
ssl = SSL.Connection(ctx, sock)
|
||||
ssl.connect((self.host, self.port))
|
||||
ssl.do_handshake()
|
||||
self.sock = FakeSocket(sock, ssl)
|
||||
|
||||
|
||||
class SSLSocket(httplib.HTTP):
|
||||
"""
|
||||
This is more or less equivalent to the httplib.HTTPS class, we juse
|
||||
use our own connection provider.
|
||||
"""
|
||||
_connection_class = SSLConnection
|
||||
|
||||
def __init__(self, host='', port=None, key_file=None, cert_file=None,
|
||||
ca_file=None, 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
|
||||
|
||||
conn = NSSHTTPS(host, 443, dbdir="/etc/pki/nssdb")
|
||||
conn.connect()
|
||||
return conn
|
||||
|
||||
class KerbTransport(SSLTransport):
|
||||
"""
|
||||
@@ -417,7 +298,7 @@ class xmlclient(Connectible):
|
||||
error=e.faultString,
|
||||
server=self.env.xmlrpc_uri,
|
||||
)
|
||||
except socket.error, e:
|
||||
raise NetworkError(uri=self.env.xmlrpc_uri, error=e.args[1])
|
||||
except NSPRError, e:
|
||||
raise NetworkError(uri=self.env.xmlrpc_uri, error=str(e))
|
||||
except ProtocolError, e:
|
||||
raise NetworkError(uri=self.env.xmlrpc_uri, error=e.errmsg)
|
||||
|
||||
@@ -22,9 +22,9 @@ import httplib
|
||||
import xml.dom.minidom
|
||||
from ipapython import nsslib
|
||||
import nss.nss as nss
|
||||
from nss.error import NSPRError
|
||||
from ipalib.errors import NetworkError, CertificateOperationError
|
||||
from urllib import urlencode
|
||||
import socket
|
||||
import logging
|
||||
|
||||
def get_ca_certchain(ca_host=None):
|
||||
@@ -76,10 +76,11 @@ def https_request(host, port, url, secdir, password, nickname, **kw):
|
||||
"Accept": "text/plain"}
|
||||
try:
|
||||
conn = nsslib.NSSConnection(host, port, dbdir=secdir)
|
||||
conn.sslsock.set_client_auth_data_callback(nsslib.client_auth_data_callback,
|
||||
nickname,
|
||||
password, nss.get_default_certdb())
|
||||
conn.sock.set_client_auth_data_callback(nsslib.client_auth_data_callback,
|
||||
nickname,
|
||||
password, nss.get_default_certdb())
|
||||
conn.set_debuglevel(0)
|
||||
conn.connect()
|
||||
conn.request("POST", url, post, request_headers)
|
||||
|
||||
res = conn.getresponse()
|
||||
@@ -122,8 +123,8 @@ def http_request(host, port, url, **kw):
|
||||
http_headers = res.msg.dict
|
||||
http_body = res.read()
|
||||
conn.close()
|
||||
except socket.error, e:
|
||||
raise NetworkError(uri=uri, error=e.args[1])
|
||||
except NSPRError, e:
|
||||
raise NetworkError(uri=uri, error=str(e))
|
||||
|
||||
logging.debug('request status %d', http_status)
|
||||
logging.debug('request reason_phrase %r', http_reason_phrase)
|
||||
|
||||
@@ -1,185 +0,0 @@
|
||||
# This is a forward backport of the Python2.5 uuid module. It isn't available
|
||||
# in Python 2.6
|
||||
|
||||
# The next several classes are used to define FakeSocket, a socket-like
|
||||
# interface to an SSL connection.
|
||||
|
||||
# The primary complexity comes from faking a makefile() method. The
|
||||
# standard socket makefile() implementation calls dup() on the socket
|
||||
# file descriptor. As a consequence, clients can call close() on the
|
||||
# parent socket and its makefile children in any order. The underlying
|
||||
# socket isn't closed until they are all closed.
|
||||
|
||||
# The implementation uses reference counting to keep the socket open
|
||||
# until the last client calls close(). SharedSocket keeps track of
|
||||
# the reference counting and SharedSocketClient provides an constructor
|
||||
# and close() method that call incref() and decref() correctly.
|
||||
|
||||
import socket
|
||||
import errno
|
||||
from httplib import UnimplementedFileMode, HTTPException
|
||||
|
||||
error = HTTPException
|
||||
|
||||
class SharedSocket:
|
||||
def __init__(self, sock):
|
||||
self.sock = sock
|
||||
self._refcnt = 0
|
||||
|
||||
def incref(self):
|
||||
self._refcnt += 1
|
||||
|
||||
def decref(self):
|
||||
self._refcnt -= 1
|
||||
assert self._refcnt >= 0
|
||||
if self._refcnt == 0:
|
||||
self.sock.close()
|
||||
|
||||
def __del__(self):
|
||||
self.sock.close()
|
||||
|
||||
class SharedSocketClient:
|
||||
|
||||
def __init__(self, shared):
|
||||
self._closed = 0
|
||||
self._shared = shared
|
||||
self._shared.incref()
|
||||
self._sock = shared.sock
|
||||
|
||||
def close(self):
|
||||
if not self._closed:
|
||||
self._shared.decref()
|
||||
self._closed = 1
|
||||
self._shared = None
|
||||
|
||||
class SSLFile(SharedSocketClient):
|
||||
"""File-like object wrapping an SSL socket."""
|
||||
|
||||
BUFSIZE = 8192
|
||||
|
||||
def __init__(self, sock, ssl, bufsize=None):
|
||||
SharedSocketClient.__init__(self, sock)
|
||||
self._ssl = ssl
|
||||
self._buf = ''
|
||||
self._bufsize = bufsize or self.__class__.BUFSIZE
|
||||
|
||||
def _read(self):
|
||||
buf = ''
|
||||
# put in a loop so that we retry on transient errors
|
||||
while True:
|
||||
try:
|
||||
buf = self._ssl.read(self._bufsize)
|
||||
except socket.sslerror, err:
|
||||
if (err[0] == socket.SSL_ERROR_WANT_READ
|
||||
or err[0] == socket.SSL_ERROR_WANT_WRITE):
|
||||
continue
|
||||
if (err[0] == socket.SSL_ERROR_ZERO_RETURN
|
||||
or err[0] == socket.SSL_ERROR_EOF):
|
||||
break
|
||||
raise
|
||||
except socket.error, err:
|
||||
if err[0] == errno.EINTR:
|
||||
continue
|
||||
if err[0] == errno.EBADF:
|
||||
# XXX socket was closed?
|
||||
break
|
||||
raise
|
||||
else:
|
||||
break
|
||||
return buf
|
||||
|
||||
def read(self, size=None):
|
||||
L = [self._buf]
|
||||
avail = len(self._buf)
|
||||
while size is None or avail < size:
|
||||
s = self._read()
|
||||
if s == '':
|
||||
break
|
||||
L.append(s)
|
||||
avail += len(s)
|
||||
alldata = "".join(L)
|
||||
if size is None:
|
||||
self._buf = ''
|
||||
return alldata
|
||||
else:
|
||||
self._buf = alldata[size:]
|
||||
return alldata[:size]
|
||||
|
||||
def readline(self):
|
||||
L = [self._buf]
|
||||
self._buf = ''
|
||||
while 1:
|
||||
i = L[-1].find("\n")
|
||||
if i >= 0:
|
||||
break
|
||||
s = self._read()
|
||||
if s == '':
|
||||
break
|
||||
L.append(s)
|
||||
if i == -1:
|
||||
# loop exited because there is no more data
|
||||
return "".join(L)
|
||||
else:
|
||||
alldata = "".join(L)
|
||||
# XXX could do enough bookkeeping not to do a 2nd search
|
||||
i = alldata.find("\n") + 1
|
||||
line = alldata[:i]
|
||||
self._buf = alldata[i:]
|
||||
return line
|
||||
|
||||
def readlines(self, sizehint=0):
|
||||
total = 0
|
||||
inlist = []
|
||||
while True:
|
||||
line = self.readline()
|
||||
if not line:
|
||||
break
|
||||
inlist.append(line)
|
||||
total += len(line)
|
||||
if sizehint and total >= sizehint:
|
||||
break
|
||||
return inlist
|
||||
|
||||
def fileno(self):
|
||||
return self._sock.fileno()
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
line = self.readline()
|
||||
if not line:
|
||||
raise StopIteration
|
||||
return line
|
||||
|
||||
class FakeSocket(SharedSocketClient):
|
||||
|
||||
class _closedsocket:
|
||||
def __getattr__(self, name):
|
||||
raise error(9, 'Bad file descriptor')
|
||||
|
||||
def __init__(self, sock, ssl):
|
||||
sock = SharedSocket(sock)
|
||||
SharedSocketClient.__init__(self, sock)
|
||||
self._ssl = ssl
|
||||
|
||||
def close(self):
|
||||
SharedSocketClient.close(self)
|
||||
self._sock = self.__class__._closedsocket()
|
||||
|
||||
def makefile(self, mode, bufsize=None):
|
||||
if mode != 'r' and mode != 'rb':
|
||||
raise UnimplementedFileMode()
|
||||
return SSLFile(self._shared, self._ssl, bufsize)
|
||||
|
||||
def send(self, stuff, flags = 0):
|
||||
return self._ssl.write(stuff)
|
||||
|
||||
sendall = send
|
||||
|
||||
def recv(self, len = 1024, flags = 0):
|
||||
return self._ssl.read(len)
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self._sock, attr)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Authors: Rob Crittenden <rcritten@redhat.com>
|
||||
# John Dennis <jdennis@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2009 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
@@ -19,19 +20,75 @@
|
||||
|
||||
import httplib
|
||||
import getpass
|
||||
import socket
|
||||
import logging
|
||||
|
||||
from nss.error import NSPRError
|
||||
import nss.io as io
|
||||
import nss.nss as nss
|
||||
import nss.ssl as ssl
|
||||
|
||||
try:
|
||||
from httplib import SSLFile
|
||||
from httplib import FakeSocket
|
||||
except ImportError:
|
||||
from ipapython.ipasslfile import SSLFile
|
||||
from ipapython.ipasslfile import FakeSocket
|
||||
def auth_certificate_callback(sock, check_sig, is_server, certdb):
|
||||
cert_is_valid = False
|
||||
|
||||
cert = sock.get_peer_certificate()
|
||||
|
||||
logging.debug("auth_certificate_callback: check_sig=%s is_server=%s\n%s",
|
||||
check_sig, is_server, str(cert))
|
||||
|
||||
pin_args = sock.get_pkcs11_pin_arg()
|
||||
if pin_args is None:
|
||||
pin_args = ()
|
||||
|
||||
# Define how the cert is being used based upon the is_server flag. This may
|
||||
# seem backwards, but isn't. If we're a server we're trying to validate a
|
||||
# client cert. If we're a client we're trying to validate a server cert.
|
||||
if is_server:
|
||||
intended_usage = nss.certificateUsageSSLClient
|
||||
else:
|
||||
intended_usage = nss.certificateUsageSSLServer
|
||||
|
||||
try:
|
||||
# If the cert fails validation it will raise an exception, the errno attribute
|
||||
# will be set to the error code matching the reason why the validation failed
|
||||
# and the strerror attribute will contain a string describing the reason.
|
||||
approved_usage = cert.verify_now(certdb, check_sig, intended_usage, *pin_args)
|
||||
except Exception, e:
|
||||
logging.error('cert validation failed for "%s" (%s)', cert.subject, e.strerror)
|
||||
cert_is_valid = False
|
||||
return cert_is_valid
|
||||
|
||||
logging.debug("approved_usage = %s intended_usage = %s",
|
||||
', '.join(nss.cert_usage_flags(approved_usage)),
|
||||
', '.join(nss.cert_usage_flags(intended_usage)))
|
||||
|
||||
# Is the intended usage a proper subset of the approved usage
|
||||
if approved_usage & intended_usage:
|
||||
cert_is_valid = True
|
||||
else:
|
||||
cert_is_valid = False
|
||||
|
||||
# If this is a server, we're finished
|
||||
if is_server or not cert_is_valid:
|
||||
logging.debug('cert valid %s for "%s"', cert_is_valid, cert.subject)
|
||||
return cert_is_valid
|
||||
|
||||
# Certificate is OK. Since this is the client side of an SSL
|
||||
# connection, we need to verify that the name field in the cert
|
||||
# matches the desired hostname. This is our defense against
|
||||
# man-in-the-middle attacks.
|
||||
|
||||
hostname = sock.get_hostname()
|
||||
try:
|
||||
# If the cert fails validation it will raise an exception
|
||||
cert_is_valid = cert.verify_hostname(hostname)
|
||||
except Exception, e:
|
||||
logging.error('failed verifying socket hostname "%s" matches cert subject "%s" (%s)',
|
||||
hostname, cert.subject, e.strerror)
|
||||
cert_is_valid = False
|
||||
return cert_is_valid
|
||||
|
||||
logging.debug('cert valid %s for "%s"', cert_is_valid, cert.subject)
|
||||
return cert_is_valid
|
||||
|
||||
def client_auth_data_callback(ca_names, chosen_nickname, password, certdb):
|
||||
cert = None
|
||||
@@ -55,56 +112,32 @@ def client_auth_data_callback(ca_names, chosen_nickname, password, certdb):
|
||||
return False
|
||||
return False
|
||||
|
||||
class SSLFile(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(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):
|
||||
def __init__(self, host, port=None, 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")
|
||||
|
||||
logging.debug('%s init %s', self.__class__.__name__, host)
|
||||
nss.nss_init(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)
|
||||
self.sock = ssl.SSLSocket()
|
||||
self.sock.set_ssl_option(ssl.SSL_SECURITY, True)
|
||||
self.sock.set_ssl_option(ssl.SSL_HANDSHAKE_AS_CLIENT, True)
|
||||
|
||||
# Provide a callback which notifies us when the SSL handshake is complete
|
||||
self.sock.set_handshake_callback(self.handshake_callback)
|
||||
|
||||
# Provide a callback to verify the servers certificate
|
||||
self.sock.set_auth_certificate_callback(auth_certificate_callback,
|
||||
nss.get_default_certdb())
|
||||
|
||||
def password_callback(self, slot, retry, password):
|
||||
if not retry and password: return password
|
||||
@@ -114,43 +147,102 @@ class NSSConnection(httplib.HTTPConnection):
|
||||
"""
|
||||
Verify callback. If we get here then the certificate is ok.
|
||||
"""
|
||||
if self.debuglevel > 0:
|
||||
print "handshake complete, peer = %s" % (sock.get_peer_name())
|
||||
logging.debug("handshake complete, peer = %s", sock.get_peer_name())
|
||||
pass
|
||||
|
||||
def connect(self):
|
||||
self.sslsock.set_hostname(self.host)
|
||||
|
||||
logging.debug("connect: host=%s port=%s", self.host, self.port)
|
||||
self.sock.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)
|
||||
logging.debug("connect: %s", net_addr)
|
||||
self.sock.connect(net_addr)
|
||||
|
||||
class NSSHTTPS(httplib.HTTP):
|
||||
# We would like to use HTTP 1.1 not the older HTTP 1.0 but xmlrpclib
|
||||
# and httplib do not play well together. httplib when the protocol
|
||||
# is 1.1 will add a host header in the request. But xmlrpclib
|
||||
# always adds a host header irregardless of the HTTP protocol
|
||||
# version. That means the request ends up with 2 host headers,
|
||||
# but Apache freaks out if it sees 2 host headers, a known Apache
|
||||
# issue. httplib has a mechanism to skip adding the host header
|
||||
# (i.e. skip_host in HTTPConnection.putrequest()) but xmlrpclib
|
||||
# doesn't use it. Oh well, back to 1.0 :-(
|
||||
#
|
||||
#_http_vsn = 11
|
||||
#_http_vsn_str = 'HTTP/1.1'
|
||||
|
||||
_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):
|
||||
def __init__(self, host='', port=None, strict=None, dbdir=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
|
||||
self._setup(self._connection_class(host, port, strict, dbdir=dbdir))
|
||||
|
||||
class NSPRConnection(httplib.HTTPConnection):
|
||||
default_port = httplib.HTTPConnection.default_port
|
||||
|
||||
def __init__(self, host, port=None, strict=None):
|
||||
httplib.HTTPConnection.__init__(self, host, port, strict)
|
||||
|
||||
logging.debug('%s init %s', self.__class__.__name__, host)
|
||||
nss.nss_init_nodb()
|
||||
|
||||
self.sock = io.Socket()
|
||||
def connect(self):
|
||||
logging.debug("connect: host=%s port=%s", self.host, self.port)
|
||||
net_addr = io.NetworkAddress(self.host, self.port)
|
||||
logging.debug("connect: %s", net_addr)
|
||||
self.sock.connect(net_addr)
|
||||
|
||||
class NSPRHTTP(httplib.HTTP):
|
||||
_http_vsn = 11
|
||||
_http_vsn_str = 'HTTP/1.1'
|
||||
|
||||
_connection_class = NSPRConnection
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
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()
|
||||
logging.basicConfig(level=logging.DEBUG,
|
||||
format='%(asctime)s %(levelname)-8s %(message)s',
|
||||
datefmt='%m-%d %H:%M',
|
||||
filename='nsslib.log',
|
||||
filemode='a')
|
||||
# Create a seperate logger for the console
|
||||
console_logger = logging.StreamHandler()
|
||||
console_logger.setLevel(logging.DEBUG)
|
||||
# set a format which is simpler for console use
|
||||
formatter = logging.Formatter('%(levelname)s %(message)s')
|
||||
console_logger.setFormatter(formatter)
|
||||
# add the handler to the root logger
|
||||
logging.getLogger('').addHandler(console_logger)
|
||||
logging.info("Start")
|
||||
|
||||
if False:
|
||||
conn = NSSConnection("www.verisign.com", 443, dbdir="/etc/pki/nssdb")
|
||||
conn.set_debuglevel(1)
|
||||
conn.connect()
|
||||
conn.request("GET", "/")
|
||||
response = conn.getresponse()
|
||||
print response.status
|
||||
#print response.msg
|
||||
print response.getheaders()
|
||||
data = response.read()
|
||||
#print data
|
||||
conn.close()
|
||||
|
||||
if True:
|
||||
h = NSSHTTPS("www.verisign.com", 443, dbdir="/etc/pki/nssdb")
|
||||
h.connect()
|
||||
h.putrequest('GET', '/')
|
||||
h.endheaders()
|
||||
http_status, http_reason, headers = h.getreply()
|
||||
print "status = %s %s" % (http_status, http_reason)
|
||||
print "headers:\n%s" % headers
|
||||
f = h.getfile()
|
||||
data = f.read() # Get the raw HTML
|
||||
f.close()
|
||||
#print data
|
||||
|
||||
@@ -125,30 +125,6 @@ def import_pkcs12(input_file, input_passwd, cert_database,
|
||||
"-k", cert_passwd,
|
||||
"-w", input_passwd])
|
||||
|
||||
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, e:
|
||||
logging.debug("client auth callback failed %s" % str(e))
|
||||
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, e:
|
||||
logging.debug("client auth callback failed %s" % str(e))
|
||||
return False
|
||||
return False
|
||||
|
||||
def get_value(s):
|
||||
"""
|
||||
Parse out a name/value pair from a Javascript variable.
|
||||
|
||||
@@ -60,30 +60,6 @@ def ipa_self_signed():
|
||||
else:
|
||||
return False
|
||||
|
||||
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, e:
|
||||
logging.debug("client auth callback failed %s" % str(e))
|
||||
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, e:
|
||||
logging.debug("client auth callback failed %s" % str(e))
|
||||
return False
|
||||
return False
|
||||
|
||||
def find_cert_from_txt(cert, start=0):
|
||||
"""
|
||||
Given a cert blob (str) which may or may not contian leading and
|
||||
|
||||
Reference in New Issue
Block a user