source: TI12-security/trunk/python/ndg.security.common/ndg/security/common/wssecurity/signaturehandler/__init__.py @ 5280

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg.security.common/ndg/security/common/wssecurity/signaturehandler/__init__.py@5280
Revision 5280, 27.2 KB checked in by pjkersha, 10 years ago (diff)

Further improvements to the authorization middleware:

  • PEPFilter no longer explicitly calls the PEPResultHandlerMiddleware (This latter class is the WSGI component which handles the access denied response that the server returns). This is not necessary as it can set a 403 response in order to trigger multiHandlerIntercept callback function set in the MultiHandler? instance. This responds to all 403 type status codes by invoking the PEPResultHandlerMiddleware.
  • ndg.security.common.authz.msi: improvements to the PDP, PIP and Response classes.
  • ndg.security.test.integration.dap: added integration test for secured pyDAP service
Line 
1""" Base class for the WS-Security digital signature handlers - to allow
2sharing of common code
3
4NERC DataGrid Project
5"""
6__author__ = "C Byrom"
7__date__ = "18/08/08"
8__copyright__ = ""
9__license__ = "BSD - see LICENSE file in top-level directory"
10__contact__ = "Philip.Kershaw@stfc.ac.uk"
11__revision__ = '$Id: $'
12
13import re
14
15# Digest and signature/verify
16from sha import sha
17from M2Crypto import X509, BIO, RSA
18import base64
19
20import os
21
22import ZSI
23from ZSI.wstools.Namespaces import ENCRYPTION, WSU
24from ZSI.wstools.Namespaces import OASIS as _OASIS
25from ConfigParser import RawConfigParser
26
27# Enable settings from a config file
28from ndg.security.common.wssecurity import WSSecurityConfig
29
30from ndg.security.common.X509 import X509Cert, X509CertParse, X509CertRead, \
31X509Stack, X509StackParseFromDER
32
33from datetime import datetime, timedelta
34import logging
35log = logging.getLogger(__name__)
36
37
38class _ENCRYPTION(ENCRYPTION):
39    '''Derived from ENCRYPTION class to add in extra 'tripledes-cbc' - is this
40    any different to 'des-cbc'?  ENCRYPTION class implies that it is the same
41    because it's assigned to 'BLOCK_3DES' ??'''
42    BLOCK_TRIPLEDES = "http://www.w3.org/2001/04/xmlenc#tripledes-cbc"
43
44class _WSU(WSU):
45    '''Try different utility namespace for use with WebSphere'''
46    #UTILITY = "http://schemas.xmlsoap.org/ws/2003/06/utility"
47    UTILITY = ("http://docs.oasis-open.org/wss/2004/01/"
48               "oasis-200401-wss-wssecurity-utility-1.0.xsd")
49
50class OASIS(_OASIS):
51    # wss4j 1.5.3
52    WSSE11 = ("http://docs.oasis-open.org/wss/"
53              "oasis-wss-wssecurity-secext-1.1.xsd")
54    # wss4j 1.5.1
55#    WSSE11 = ("http://docs.oasis-open.org/wss/2005/xx/"
56#              "oasis-2005xx-wss-wssecurity-secext-1.1.xsd")
57
58
59class WSSecurityError(Exception):
60    """For WS-Security generic exceptions not covered by other exception
61    classes in this module"""
62    def __init__(self, errorMessage):
63        log.warning(errorMessage)
64        super(WSSecurityError, self).__init__(errorMessage)
65
66class InvalidCertChain(WSSecurityError):   
67    """Raised from SignatureHandler.verify if the certificate submitted to
68    verify a signature is not from a known CA"""
69   
70class VerifyError(WSSecurityError):
71    """Raised from SignatureHandler.verify if an error occurs in the signature
72    verification"""
73 
74class TimestampError(WSSecurityError):
75    """Raised from SignatureHandler._verifyTimestamp if there is a problem with
76    the created or expiry times in an input message Timestamp"""
77   
78class InvalidSignature(WSSecurityError):
79    """Raised from verify method for an invalid signature"""
80
81class SignatureError(WSSecurityError):
82    """Flag if an error occurs during signature generation"""
83
84class NoSignatureFound(WSSecurityError):
85    """Raise from SignatureHandler.verify if inbound message is not signed"""
86
87
88class BaseSignatureHandler(object):
89    """Class to handle signature and verification of signature with
90    WS-Security
91   
92    @cvar binSecTokValType: supported ValueTypes for BinarySecurityToken
93    element in WSSE header
94    @type binSecTokValType: dict
95   
96    @ivar addTimestamp: set to true to add a timestamp to outbound messages
97    @type addTimestamp: bool
98
99    @ivar applySignatureConfirmation: for servers - set this flag to enable the
100    signature value of a request to be recorded and included with a
101    SignatureConfirmation element in the response.
102    @type applySignatureConfirmation: bool
103   
104    @param b64EncSignatureValue: base 64 encoded signature value for the last
105    message verified
106    @type b64EncSignatureValue: string/None"""
107
108    _binSecTokEncType = ("http://docs.oasis-open.org/wss/2004/01/"
109                         "oasis-200401-wss-soap-message-security-1.0#"
110                         "Base64Binary")
111   
112    binSecTokValType = {
113        "X509PKIPathv1": OASIS.X509TOKEN.X509PKIPathv1,
114        "X509":          OASIS.X509TOKEN.X509,
115        "X509v3":        OASIS.X509TOKEN.X509+"v3"
116    }
117
118
119    def __init__(self, cfg=None, cfgFileSection='DEFAULT', cfgFilePrefix='',
120                 cfgClass=WSSecurityConfig, **kw):
121        '''
122        @keyword reqBinSecTokValType: set the ValueType for the
123        BinarySecurityToken added to the WSSE header for a signed message.  See
124        __setReqBinSecTokValType method and binSecTokValType class variable
125        for options.  binSecTokValType determines whether signingCert or
126        signingCertChain attributes will be used.       
127        @type binSecTokValType: string
128       
129        @keyword verifyingCert: X.509 certificate used by verify method to
130        verify a message.  This argument can be omitted if the message to
131        be verified contains the X.509 certificate in the
132        BinarySecurityToken element.  In this case, the cert read from the
133        message will be assigned to the verifyingCert attribute.
134        @type verifyingCert: M2Crypto.X509.X509 /
135        ndg.security.common.X509.X509Cert
136       
137        @keyword verifyingCertFilePath: alternative input to the above, pass
138        the file path to the certificate stored in a file
139        @type verifyingCertFilePath: string
140       
141        @keyword signingCert: certificate associated with private key used to
142        sign a message.  The sign method will add this to the
143        BinarySecurityToken element of the WSSE header.  binSecTokValType
144        attribute must be set to 'X509' or 'X509v3' ValueTyep.  As an
145        alternative, use signingCertChain - see below...
146        @type signingCert: M2Crypto.X509.X509 /
147        ndg.security.common.X509.X509Cert
148       
149        @keyword signingCertFilePath: alternative input to the above, pass
150        the file path to the certificate stored in a file
151        @type signingCertFilePath: string
152       
153        @keyword signingCertChain: pass a list of certificates constituting a
154        chain of trust from the certificate used to verifying the signature
155        backward to the CA cert.  The CA cert need not be included.  To use
156        this option, reqBinSecTokValType must be set to the 'X509PKIPathv1'
157        ValueType
158        @type signingCertChain: list or tuple
159       
160        @keyword signingPriKey: private key used to be sign method to sign
161        message
162        @type signingPriKey: M2Crypto.RSA.
163       
164        @keyword signingPriKeyFilePath: equivalent to the above but pass
165        private key from PEM file
166        @type signingPriKeyFilePath: string
167       
168        @keyword signingPriKeyPwd: password protecting private key.  Set /
169        default to None if there is no password.
170        @type signingPriKeyPwd: string or None
171       
172        @keyword caCertDirPath: establish trust for signature verification.
173        This is a directory containing CA certificates.  These are used to
174        verify the certificate used to verify the message signature.
175        @type caCertDirPath: string
176       
177        @keyword caCertFilePathList: same as above except pass in a list of
178        file paths instead of a single directory name.
179        @type caCertFilePathList: list or tuple
180       
181        @keyword addTimestamp: set to true to add a timestamp to outbound
182        messages
183        @type addTimestamp: bool
184       
185        @keyword applySignatureConfirmation: for servers - set this flag to
186        enable the signature value of a request to be recorded and included
187        with a SignatureConfirmation element in the response.
188        @type : bool
189       
190        @param refC14nInclNS: list of namespaces to include in reference
191        Canonicalization.
192        @type refC14nInclNS: list
193       
194        @param signedInfoC14nInclNS: list of namespaces to include in
195        Signed Info Canonicalization.
196        @type signedInfoC14nInclNS: list
197        '''
198        log.debug("BaseSignatureHandler.__init__ ...")
199
200        # WSSecurityConfig is the default class for reading config params but
201        # alternative derivative class may be passed in instead.
202        if not issubclass(cfgClass, WSSecurityConfig):
203            raise TypeError("%s is not a sub-class of WSSecurityConfig" % 
204                            cfgClass)
205       
206        # Read parameters from config file if set
207        if isinstance(cfg, basestring):
208            log.debug("BaseSignatureHandler.__init__: config file path input "
209                      "...")
210            self.cfg = cfgClass()
211            self.cfg.read(cfg)
212            self.cfg.parse(section=cfgFileSection, prefix=cfgFilePrefix)
213
214        elif isinstance(cfg, RawConfigParser):
215            log.debug("BaseSignatureHandler.__init__: config object input ...")
216            self.cfg = cfgClass(cfg=cfg)
217            self.cfg.parse(section=cfgFileSection, prefix=cfgFilePrefix)
218           
219        elif isinstance(cfg, WSSecurityConfig):
220            log.debug("BaseSignatureHandler.__init__:  WSSSecurityConfig "
221                      "object input ...")
222            self.cfg = cfg
223        else:
224            self.cfg = cfgClass()
225               
226        # Also update config from keywords set
227        log.debug("BaseSignatureHandler.__init__: updating config from "
228                  "keywords...")
229       
230        # Filter keywords if a prefix is set removing any that don't start with
231        # the prefix given
232        self.cfg.update(kw, prefix=cfgFilePrefix)
233       
234        # set default value type, if none specified in config file
235        if not self.cfg['reqBinSecTokValType']:
236            self.cfg['reqBinSecTokValType'] = "X509v3"
237           
238        self.reqBinSecTokValType = self.cfg['reqBinSecTokValType']
239
240        # Set keywords for canonicalization of SignedInfo and reference
241        # elements
242        self.refC14nKw = {'inclusive_namespaces': self.cfg['refC14nInclNS']}
243
244        self.signedInfoC14nKw = {'inclusive_namespaces': 
245                                 self.cfg['signedInfoC14nInclNS']}
246
247        self.verifyingCert = self.cfg['verifyingCert']
248        self.verifyingCertFilePath = self.cfg['verifyingCertFilePath']
249       
250        self.signingCert = self.cfg['signingCert']
251        self.signingCertFilePath = self.cfg['signingCertFilePath']
252
253        self.signingCertChain = self.cfg['signingCertChain']
254             
255        # MUST be set before _setSigningPriKeyFilePath / _setSigningPriKey
256        # are called
257        self.signingPriKeyPwd = self.cfg['signingPriKeyPwd']
258       
259        if self.cfg.get('signingPriKey'):
260            # Don't allow None for private key setting
261            self.signingPriKey = self.cfg['signingPriKey']
262           
263        self.signingPriKeyFilePath = self.cfg['signingPriKeyFilePath']
264       
265        # CA certificate(s) for verification of X.509 certificate used with
266        # signature.
267        if self.cfg.get('caCertDirPath'):
268            self.caCertDirPath = self.cfg['caCertDirPath']
269           
270        elif self.cfg.get('caCertFilePathList'):
271            self.caCertFilePathList = self.cfg['caCertFilePathList']
272       
273        self.addTimestamp = self.cfg['addTimestamp']
274       
275        # set default value, if none specified in config file
276        if not self.cfg['applySignatureConfirmation']:
277            self.cfg['applySignatureConfirmation'] = False
278
279        self.applySignatureConfirmation=self.cfg['applySignatureConfirmation']
280        self.b64EncSignatureValue = None
281       
282        log.debug("WSSE Config = %s" % self.cfg)
283
284               
285    def _setReqBinSecTokValType(self, value):
286        """Set ValueType attribute for BinarySecurityToken used in a request
287         
288        @type value: string
289        @param value: name space for BinarySecurityToken ValueType check
290        'binSecTokValType' class variable for supported types.  Input can be
291        shortened to binSecTokValType keyword if desired.
292        """
293        log.debug("Setting reqBinSecTokValType - to %s" %value)
294        if value in self.__class__.binSecTokValType:
295            self._reqBinSecTokValType = self.__class__.binSecTokValType[value]
296 
297        elif value in self.__class__.binSecTokValType.values():
298            self._reqBinSecTokValType = value
299        else:
300            raise WSSecurityError('Request BinarySecurityToken ValueType '
301                                  '"%s" not recognised' % value)
302           
303    def _getReqBinSecTokValType(self):
304        """
305        Get ValueType attribute for BinarySecurityToken used in a request
306        """
307        log.debug("Getting reqBinSecTokValType value")
308        if hasattr(self, '_reqBinSecTokValType'):
309            return self._reqBinSecTokValType
310        else:
311            return ""
312       
313    reqBinSecTokValType = property(fset=_setReqBinSecTokValType,
314                                   fget=_getReqBinSecTokValType,
315         doc="ValueType attribute for BinarySecurityToken used in request")
316       
317
318    def __checkC14nKw(self, kw):
319        """Check keywords for canonicalization in signing process - generic
320        method for setting keywords for reference element and SignedInfo
321        element C14N
322       
323        @type kw: dict
324        @param kw: keyword used with ZSI.wstools.Utility.Canonicalization"""
325       
326        # Check for dict/None - Set to None in order to use inclusive
327        # canonicalization
328        if kw is not None and not isinstance(kw, dict):
329            # Otherwise keywords must be a dictionary
330            raise AttributeError("Expecting dictionary type for reference "
331                                 "C14N keywords")
332               
333        elif kw.get('inclusive_namespaces') and \
334             not isinstance(kw['inclusive_namespaces'], (list, tuple)):
335            raise AttributeError('Expecting list or tuple of prefix names for '
336                                 '"%s" keyword' % 'inclusive_namespaces')
337       
338               
339    def _setRefC14nKw(self, kw):
340        """Set keywords for canonicalization of reference elements in the
341        signing process"""
342        self.__checkC14nKw(kw)                   
343        self._refC14nKw = kw
344       
345    def _getRefC14nKw(self):
346        if hasattr(self, '_refC14nKw'):
347            return self._refC14nKw
348        else:
349            return {}
350       
351    refC14nKw = property(fset=_setRefC14nKw,
352                         fget=_getRefC14nKw,
353                         doc="Keywords for C14N of reference elements")
354       
355               
356    def _setSignedInfoC14nKw(self, kw):
357        """Set keywords for canonicalization of SignedInfo element in the
358        signing process"""
359        self.__checkC14nKw(kw)                   
360        self._signedInfoC14nKw = kw
361       
362    def _getSignedInfoC14nKw(self):
363        if hasattr(self, '_signedInfoC14nKw'):
364            return self._signedInfoC14nKw
365        else:
366            return {}
367       
368    signedInfoC14nKw = property(fset=_setSignedInfoC14nKw,
369                                fget=_getSignedInfoC14nKw,
370                                doc="Keywords for C14N of SignedInfo element")
371
372
373    def _refC14nIsExcl(self):
374        '''
375        @rtype: bool
376        @return: true if Exclusive C14N is set as algorithm to apply to
377        reference elements
378        '''
379        # TODO: alter logic here if inclusive C14N is re-instated.
380        return True
381               
382    refC14nIsExcl = property(fget=_refC14nIsExcl,
383    doc="Return True/False C14N for reference elements set to exclusive type")
384
385     
386    def _signedInfoC14nIsExcl(self):
387        '''
388        @rtype: bool
389        @return: true if Exclusive C14N is set as algorithm to apply to
390        the signed info elements of the XML Digital Signature
391        '''
392        # TODO: alter logic here if inclusive C14N is re-instated.
393        return True
394       
395    signedInfoC14nIsExcl = property(fget=_signedInfoC14nIsExcl,
396                                    doc="Return True/False C14N for "
397                                    "SignedInfo element set to exclusive type")
398   
399   
400    def _setCert(self, cert):
401        """filter and convert input cert to signing verifying cert set
402        property methods.  For signingCert, set to None if it is not to be
403        included in the SOAP header.  For verifyingCert, set to None if this
404        cert can be expected to be retrieved from the SOAP header of the
405        message to be verified
406       
407        @type: ndg.security.common.X509.X509Cert / M2Crypto.X509.X509 /
408        PEM encoded string or None
409        @param cert: X.509 certificate. 
410       
411        @rtype ndg.security.common.X509.X509Cert
412        @return X.509 certificate object"""
413       
414        if not cert or isinstance(cert, X509Cert):
415            # ndg.security.common.X509.X509Cert type / None
416            x509Cert = cert
417           
418        elif isinstance(cert, X509.X509):
419            # M2Crypto.X509.X509 type
420            x509Cert = X509Cert(m2CryptoX509=cert)
421           
422        elif isinstance(cert, basestring):
423            # Nb. Assume PEM encoded string!
424            x509Cert = X509CertParse(cert)
425       
426        else:
427            raise AttributeError("X.509 Cert. must be type: ndg.security."
428                                 "common.X509.X509Cert, M2Crypto.X509.X509 or "
429                                 "a base64 encoded string")
430       
431        # Check for expired certificate
432        if x509Cert:   
433            x509Cert.isValidTime(raiseExcep=True)
434           
435        return x509Cert
436
437   
438    def _getVerifyingCert(self):
439        '''Return X.509 cert object corresponding to cert used to verify the
440        signature in the last call to verify
441       
442         * Cert will correspond to one used in the LATEST call to verify, on
443         the next call it will be replaced
444         * if verify hasn't been called, the cert will be None
445       
446        @rtype: M2Crypto.X509.X509
447        @return: certificate object
448        '''
449        return self._verifyingCert
450
451
452    def _setVerifyingCert(self, verifyingCert):
453        "Set property method for X.509 cert. used to verify a signature"
454        self._verifyingCert = self._setCert(verifyingCert)
455       
456        # Reset file path as it may no longer apply
457        self._verifyingCertFilePath = None
458       
459    verifyingCert = property(fset=_setVerifyingCert,
460                             fget=_getVerifyingCert,
461                             doc="Set X.509 Cert. for verifying signature")
462
463
464    def _setVerifyingCertFilePath(self, verifyingCertFilePath):
465        "Set method for Service X.509 cert. file path property"
466        if verifyingCertFilePath:
467            if isinstance(verifyingCertFilePath, basestring):
468                self._verifyingCert = X509CertRead(verifyingCertFilePath)
469            else:
470                raise AttributeError, "X.509 Cert file path is not a valid string"
471       
472        self._verifyingCertFilePath = verifyingCertFilePath
473       
474    verifyingCertFilePath = property(fset=_setVerifyingCertFilePath,
475                    doc="file path of X.509 Cert. for verifying signature")
476
477   
478    def _getSigningCert(self):
479        '''Return X.509 certificate object corresponding to certificate used
480        with signature
481       
482        @rtype: M2Crypto.X509.X509
483        @return: certificate object
484        '''
485        return self._signingCert
486
487
488    def _setSigningCert(self, signingCert):
489        "Set property method for X.509 cert. to be included with signature"
490        self._signingCert = self._setCert(signingCert)
491   
492        # Reset file path as it may no longer apply
493        self._signingCertFilePath = None
494       
495    signingCert = property(fget=_getSigningCert,
496                           fset=_setSigningCert,
497                           doc="X.509 Certificate to include signature")
498
499 
500    def _setSigningCertFilePath(self, signingCertFilePath):
501        "Set signature X.509 certificate property method"
502       
503        if isinstance(signingCertFilePath, basestring):
504            self._signingCert = X509CertRead(signingCertFilePath)
505           
506        elif signingCertFilePath is not None:
507            raise AttributeError("Signature X.509 certificate file path must "
508                                 "be a valid string")
509       
510        self._signingCertFilePath = signingCertFilePath
511       
512       
513    signingCertFilePath = property(fset=_setSigningCertFilePath,
514                   doc="File path X.509 cert. to include with signed message")
515
516   
517    def _setSigningCertChain(self, signingCertChain):
518        '''Signature set-up with "X509PKIPathv1" BinarySecurityToken
519        ValueType.  Use an X.509 Stack to store certificates that make up a
520        chain of trust to certificate used to verify a signature
521       
522        @type signingCertChain: list or tuple of M2Crypto.X509.X509Cert or
523        ndg.security.common.X509.X509Cert types.
524        @param signingCertChain: list of certificate objects making up the
525        chain of trust.  The last certificate is the one associated with the
526        private key used to sign the message.'''
527       
528        if not isinstance(signingCertChain, (list, tuple)):
529            log.warning('Expecting a list or tuple for "signingCertChain" - '
530                        'ignoring value set, "%s"' % signingCertChain)
531            self._signingCertChain = None
532            return
533       
534        self._signingCertChain = X509Stack()
535           
536        for cert in signingCertChain:
537            self._signingCertChain.push(cert)
538           
539    def _getSigningCertChain(self):
540        return self._signingCertChain
541   
542    signingCertChain = property(fset=_setSigningCertChain,
543                                fget=_getSigningCertChain,
544                                doc="Cert.s in chain of trust to cert. used "
545                                    "to verify msg.")
546
547 
548    def _setSigningPriKeyPwd(self, signingPriKeyPwd):
549        "Set method for private key file password used to sign message"
550        if signingPriKeyPwd is not None and \
551           not isinstance(signingPriKeyPwd, basestring):
552            raise AttributeError("Signing private key password must be None "
553                                 "or a valid string")
554       
555        self._signingPriKeyPwd = signingPriKeyPwd
556
557    def _getSigningPriKeyPwd(self):
558        if hasattr(self, '_signingPriKeyPwd'):
559            return self._signingPriKeyPwd
560        else:
561            return ""
562       
563    signingPriKeyPwd = property(fset=_setSigningPriKeyPwd,
564                                fget=_getSigningPriKeyPwd,
565                                doc="Password protecting private key file "
566                                    "used to sign message")
567
568 
569    def _setSigningPriKey(self, signingPriKey):
570        """Set method for client private key
571       
572        Nb. if input is a string, signingPriKeyPwd will need to be set if
573        the key is password protected.
574       
575        @type signingPriKey: M2Crypto.RSA.RSA / string
576        @param signingPriKey: private key used to sign message"""
577       
578        if isinstance(signingPriKey, basestring):
579            pwdCallback = lambda *ar, **kw: self._signingPriKeyPwd
580            self._signingPriKey = RSA.load_key_string(signingPriKey,
581                                                       callback=pwdCallback)
582
583        elif isinstance(signingPriKey, RSA.RSA):
584            self._signingPriKey = signingPriKey
585                   
586        else:
587            raise AttributeError("Signing private key must be a valid "
588                                  "M2Crypto.RSA.RSA type or a string")
589               
590    def _getSigningPriKey(self):
591        return self._signingPriKey
592
593    signingPriKey = property(fset=_setSigningPriKey,
594                             fget=_getSigningPriKey,
595                             doc="Private key used to sign outbound message")
596
597 
598    def _setSigningPriKeyFilePath(self, signingPriKeyFilePath):
599        """Set method for client private key file path
600       
601        signingPriKeyPwd MUST be set prior to a call to this method"""
602        if isinstance(signingPriKeyFilePath, basestring):                           
603            try:
604                # Read Private key to sign with   
605                priKeyFile = BIO.File(open(signingPriKeyFilePath)) 
606                pwdCallback = lambda *ar, **kw: self._signingPriKeyPwd                                           
607                self._signingPriKey = RSA.load_key_bio(priKeyFile, 
608                                                        callback=pwdCallback)           
609            except Exception, e:
610                raise AttributeError("Setting private key for signature: %s"%e)
611       
612        elif signingPriKeyFilePath is not None:
613            raise AttributeError("Private key file path must be a valid "
614                                 "string or None")
615       
616        self.__signingPriKeyFilePath = signingPriKeyFilePath
617       
618    signingPriKeyFilePath = property(fset=_setSigningPriKeyFilePath,
619                      doc="File path for private key used to sign message")
620
621    def __caCertIsSet(self):
622        '''Check for CA certificate set (X.509 Stack has been created)'''
623        return hasattr(self, '_caX509Stack')
624   
625    caCertIsSet = property(fget=__caCertIsSet,
626           doc='Check for CA certificate set (X.509 Stack has been created)')
627   
628    def __appendCAX509Stack(self, caCertList):
629        '''Store CA certificates in an X.509 Stack
630       
631        @param caCertList: list or tuple
632        @type caCertList: M2Crypto.X509.X509 certificate objects'''
633       
634        if not hasattr(self, '_caX509Stack'):
635            self._caX509Stack = X509Stack()
636           
637        for cert in caCertList:
638            self._caX509Stack.push(cert)
639
640
641    def __setCAX509StackFromDir(self, caCertDir):
642        '''Read CA certificates from directory and add them to the X.509
643        stack
644       
645        @param caCertDir: string
646        @type caCertDir: directory from which to read CA certificate files'''
647       
648        # Mimic OpenSSL -CApath option which expects directory of CA files
649        # of form <Hash cert subject name>.0
650        reg = re.compile('\d+\.0')
651        try:
652            caCertList = [X509CertRead(caFile) \
653                          for caFile in os.listdir(caCertDir) \
654                          if reg.match(caFile)]
655        except Exception, e:
656            raise WSSecurityError('Loading CA certificate "%s" from CA '
657                                  'directory: %s' % (caFile, str(e)))
658                   
659        # Add to stack
660        self.__appendCAX509Stack(caCertList)
661       
662    caCertDirPath = property(fset=__setCAX509StackFromDir,
663                             doc="Dir. containing CA cert.s used for "
664                                "verification")
665
666
667    def __setCAX509StackFromCertFileList(self, caCertFilePathList):
668        '''Read CA certificates from file and add them to the X.509
669        stack
670       
671        @type caCertFilePathList: list or tuple
672        @param caCertFilePathList: list of file paths for CA certificates to
673        be used to verify certificate used to sign message'''
674       
675        if not isinstance(caCertFilePathList, (list, tuple)):
676            raise WSSecurityError('Expecting a list or tuple for '
677                                  '"caCertFilePathList"')
678
679        # Mimic OpenSSL -CApath option which expects directory of CA files
680        # of form <Hash cert subject name>.0
681        try:
682            caCertList=[X509CertRead(caFile) for caFile in caCertFilePathList]
683        except Exception, e:
684            raise WSSecurityError('Loading CA certificate "%s" from file '
685                                  'list: %s' % (caFile, str(e)))
686                   
687        # Add to stack
688        self.__appendCAX509Stack(caCertList)
689       
690    caCertFilePathList = property(fset=__setCAX509StackFromCertFileList,
691                      doc="List of CA cert. files used for verification")
692               
Note: See TracBrowser for help on using the repository browser.