source: TI12-security/trunk/python/ndg.security.common/ndg/security/common/m2CryptoSSLUtility.py @ 2884

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg.security.common/ndg/security/common/m2CryptoSSLUtility.py@2884
Revision 2884, 5.9 KB checked in by pjkersha, 13 years ago (diff)

Explicitly setting of SSL timeout avoids hanging client for calls over https

ndg.security.server/ndg/security/server/conf/sessionMgr.tac,
ndg.security.server/ndg/security/server/conf/attAuthority.tac:

  • added ref to NDGSEC_INT_DEBUG environment variable -sets service to stop in debugger at the start of each SOAP call. Service must be restarted in order for variable to be picked up

ndg.security.test/ndg/security/test/AttAuthority/siteAAttAuthorityProperties.xml,
ndg.security.test/ndg/security/test/AttAuthority/attAuthorityClientTest.cfg,
ndg.security.test/ndg/security/test/SessionMgr/sessionMgrClientTest.cfg:

  • running unit tests with https switched on to investigate timeout problems. SM calls to an AA over https currently fail with a HTTP bad status line error

ndg.security.common/ndg/security/common/AttAuthority/init.py: improve error reporting for getAttCert call.

ndg.security.common/ndg/security/common/m2CryptoSSLUtility.py:

  • added functionality to set read and write timeouts. M2Crypto default is 600s(!). Changed default to 3s
Line 
1import httplib
2import socket
3
4from M2Crypto import SSL, X509
5from M2Crypto.httpslib import HTTPSConnection as _HTTPSConnection
6
7from ndg.security.common.X509 import X509Cert, X509Stack
8
9class InvalidCertSignature(SSL.Checker.SSLVerificationError):
10    """Raise if verification against CA cert public key fails"""
11   
12
13class HostCheck(SSL.Checker.Checker, object):
14    """Override SSL.Checker.Checker to enable alternate Common Name
15    setting match for peer cert"""
16
17    def __init__(self, 
18                 peerCertDN=None, 
19                 peerCertCN=None, 
20                 caCertList=[],
21                 caCertFilePathList=[], 
22                 **kw):
23        """Override parent class __init__ to enable setting of myProxyServerDN
24        setting
25       
26        @type peerCertDN: string
27        @keyword peerCertDN: Set the expected Distinguished Name of the
28        server to avoid errors matching hostnames.  This is useful
29        where the hostname is not fully qualified
30       
31        @type peerCertCN: string
32        @keyword peerCertCN: enable alternate Common Name to peer
33        hostname
34       
35        @type caCertList: list type of M2Crypto.X509.X509 types
36        @keyword caCertList: CA X.509 certificates - if set the peer cert's
37        CA signature is verified against one of these.  At least one must
38        verify
39       
40        @type caCertFilePathList: list string types
41        @keyword caCertFilePathList: same as caCertList except input as list
42        of CA cert file paths"""
43       
44        SSL.Checker.Checker.__init__(self, **kw)
45       
46        self.peerCertDN = peerCertDN
47        self.peerCertCN = peerCertCN
48        if caCertList:
49            self.caCertList = caCertList
50        elif caCertFilePathList:
51            self.caCertFilePathList = caCertFilePathList
52           
53       
54    def __call__(self, peerCert, host=None):
55        """Carry out checks on server ID
56        @param peerCert: MyProxy server host certificate as M2Crypto.X509.X509
57        instance
58        @keyword host: name of host to check
59        """
60       
61        try:
62            SSL.Checker.Checker.__call__(self, peerCert, host=self.peerCertCN)
63           
64        except SSL.Checker.WrongHost, e:
65            # Try match against peerCertDN set
66            # file setting
67            peerCertDN='/'+peerCert.get_subject().as_text().replace(', ', '/')
68            if peerCertDN != self.peerCertDN:
69                raise e
70
71        if len(self.__caCertStack) > 0:
72            try:
73                self.__caCertStack.verifyCertChain(\
74                           x509Cert2Verify=X509Cert(m2CryptoX509=peerCert))
75            except Exception, e:
76                raise InvalidCertSignature, \
77            "Peer certificate verification against CA cert failed: "+str(e) 
78             
79        # They match - drop the exception and return all OK instead         
80        return True
81   
82   
83    def __setCACertList(self, caCertList):
84        """Set list of CA certs - peer cert must validate against at least one
85        of these"""
86        self.__caCertStack = X509Stack()
87        for caCert in caCertList:
88            self.__caCertStack.push(caCert)
89
90    caCertList = property(fset=__setCACertList,
91              doc="list of CA certs - peer cert must validate against one")
92
93
94    #_________________________________________________________________________
95    def __setCACertsFromFileList(self, caCertFilePathList):
96        '''Read CA certificates from file and add them to the X.509
97        stack
98       
99        @type caCertFilePathList: list or tuple
100        @param caCertFilePathList: list of file paths for CA certificates to
101        be used to verify certificate used to sign message'''
102       
103        if not isinstance(caCertFilePathList, list) and \
104           not isinstance(caCertFilePathList, tuple):
105            raise AttributeError, \
106                        'Expecting a list or tuple for "caCertFilePathList"'
107
108        self.__caCertStack = X509Stack()
109
110        for caCertFilePath in caCertFilePathList:
111            self.__caCertStack.push(X509.load_cert(caCertFilePath))
112       
113    caCertFilePathList = property(fset=__setCACertsFromFileList,
114    doc="list of CA cert file paths - peer cert must validate against one")
115
116
117class HTTPSConnection(_HTTPSConnection):
118
119    def __init__(self, *args, **kw):
120        '''Overload to enable setting of post connection check
121        callback to SSL.Connection'''
122        if 'postConnectionCheck' in kw:
123            self._postConnectionCheck = kw['postConnectionCheck']
124            del kw['postConnectionCheck']
125        else:
126            self._postConnectionCheck = SSL.Checker.Checker
127       
128        if 'readTimeout' in kw:
129            if not isinstance(readTimeout, SSL.timeout):
130                raise AttributeError, "readTimeout must be of type " + \
131                                      "M2Crypto.SSL.timeout" 
132            self.readTimeout = readTimeout
133            del kw['readTimeout']
134        else:
135            self.readTimeout = SSL.timeout(sec=3.) 
136             
137        if 'writeTimeout' in kw:
138            if not isinstance(writeTimeout, SSL.timeout):
139                raise AttributeError, "writeTimeout must be of type " + \
140                                      "M2Crypto.SSL.timeout" 
141            self.writeTimeout = writeTimeout
142            del kw['writeTimeout']
143        else:
144            self.writeTimeout = SSL.timeout(sec=3.)
145           
146        _HTTPSConnection.__init__(self, *args, **kw)
147       
148       
149    def connect(self):
150        '''Overload M2Crypto.httpslib.HTTPSConnection to enable
151        custom post connection check of peer certificate and socket timeout'''
152        self.sock = SSL.Connection(self.ssl_ctx)
153        self.sock.set_post_connection_check_callback(
154                                                 self._postConnectionCheck)
155   
156        self.sock.set_socket_read_timeout(self.readTimeout)
157        self.sock.set_socket_write_timeout(self.writeTimeout)
158
159        self.sock.connect((self.host, self.port))
Note: See TracBrowser for help on using the repository browser.