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

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

Working Policy Decision Point:

  • A PIP (Policy Information Point) helps the PDP by retrieving user attributes for a given Attribute Authority.
  • TODO: Session Manager calls are made over SOAP to the users session running at their home institution. This has some caching capability to avoid repeated calls to the user's Session Manager but it could host it's own Session Manager instance for improved performance
  • ndg.security.server.sessionmanager: improved UserSession? to include a timestamp on creation and timeout check via isValid() method. Added auditSessions() method to enable expired sessions to be weeded out. Changed _createUserSession to public method createUserSession. This is useful where a session needs to be created for a user who has already been authenticated.
  • ndg.security.test.config.attributeauthority: changed test attributes to urn's to namespace them.
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        log.debug("Getting verifying cert")
450        return self._verifyingCert
451
452
453    def _setVerifyingCert(self, verifyingCert):
454        "Set property method for X.509 cert. used to verify a signature"
455        log.debug("Setting verifying cert")
456        self._verifyingCert = self._setCert(verifyingCert)
457        # Reset file path as it may no longer apply
458        self._verifyingCertFilePath = None
459       
460    verifyingCert = property(fset=_setVerifyingCert,
461                             fget=_getVerifyingCert,
462                             doc="Set X.509 Cert. for verifying signature")
463
464
465    def _setVerifyingCertFilePath(self, verifyingCertFilePath):
466        "Set method for Service X.509 cert. file path property"
467        if verifyingCertFilePath:
468            if isinstance(verifyingCertFilePath, basestring):
469                self._verifyingCert = X509CertRead(verifyingCertFilePath)
470            else:
471                raise AttributeError, "X.509 Cert file path is not a valid string"
472       
473        self._verifyingCertFilePath = verifyingCertFilePath
474       
475    verifyingCertFilePath = property(fset=_setVerifyingCertFilePath,
476                    doc="file path of X.509 Cert. for verifying signature")
477
478   
479    def _getSigningCert(self):
480        '''Return X.509 certificate object corresponding to certificate used
481        with signature
482       
483        @rtype: M2Crypto.X509.X509
484        @return: certificate object
485        '''
486        return self._signingCert
487
488
489    def _setSigningCert(self, signingCert):
490        "Set property method for X.509 cert. to be included with signature"
491        self._signingCert = self._setCert(signingCert)
492   
493        # Reset file path as it may no longer apply
494        self._signingCertFilePath = None
495       
496    signingCert = property(fget=_getSigningCert,
497                           fset=_setSigningCert,
498                           doc="X.509 Certificate to include signature")
499
500 
501    def _setSigningCertFilePath(self, signingCertFilePath):
502        "Set signature X.509 certificate property method"
503       
504        if isinstance(signingCertFilePath, basestring):
505            self._signingCert = X509CertRead(signingCertFilePath)
506           
507        elif signingCertFilePath is not None:
508            raise AttributeError("Signature X.509 certificate file path must "
509                                 "be a valid string")
510       
511        self._signingCertFilePath = signingCertFilePath
512       
513       
514    signingCertFilePath = property(fset=_setSigningCertFilePath,
515                   doc="File path X.509 cert. to include with signed message")
516
517   
518    def _setSigningCertChain(self, signingCertChain):
519        '''Signature set-up with "X509PKIPathv1" BinarySecurityToken
520        ValueType.  Use an X.509 Stack to store certificates that make up a
521        chain of trust to certificate used to verify a signature
522       
523        @type signingCertChain: list or tuple of M2Crypto.X509.X509Cert or
524        ndg.security.common.X509.X509Cert types.
525        @param signingCertChain: list of certificate objects making up the
526        chain of trust.  The last certificate is the one associated with the
527        private key used to sign the message.'''
528       
529        if not isinstance(signingCertChain, (list, tuple)):
530            log.warning('Expecting a list or tuple for "signingCertChain" - '
531                        'ignoring value set, "%s"' % signingCertChain)
532            self._signingCertChain = None
533            return
534       
535        self._signingCertChain = X509Stack()
536           
537        for cert in signingCertChain:
538            self._signingCertChain.push(cert)
539           
540    def _getSigningCertChain(self):
541        return self._signingCertChain
542   
543    signingCertChain = property(fset=_setSigningCertChain,
544                                fget=_getSigningCertChain,
545                                doc="Cert.s in chain of trust to cert. used "
546                                    "to verify msg.")
547
548 
549    def _setSigningPriKeyPwd(self, signingPriKeyPwd):
550        "Set method for private key file password used to sign message"
551        if signingPriKeyPwd is not None and \
552           not isinstance(signingPriKeyPwd, basestring):
553            raise AttributeError("Signing private key password must be None "
554                                 "or a valid string")
555       
556        self._signingPriKeyPwd = signingPriKeyPwd
557
558    def _getSigningPriKeyPwd(self):
559        if hasattr(self, '_signingPriKeyPwd'):
560            return self._signingPriKeyPwd
561        else:
562            return ""
563       
564    signingPriKeyPwd = property(fset=_setSigningPriKeyPwd,
565                                fget=_getSigningPriKeyPwd,
566                                doc="Password protecting private key file "
567                                    "used to sign message")
568
569 
570    def _setSigningPriKey(self, signingPriKey):
571        """Set method for client private key
572       
573        Nb. if input is a string, signingPriKeyPwd will need to be set if
574        the key is password protected.
575       
576        @type signingPriKey: M2Crypto.RSA.RSA / string
577        @param signingPriKey: private key used to sign message"""
578       
579        if isinstance(signingPriKey, basestring):
580            pwdCallback = lambda *ar, **kw: self._signingPriKeyPwd
581            self._signingPriKey = RSA.load_key_string(signingPriKey,
582                                                       callback=pwdCallback)
583
584        elif isinstance(signingPriKey, RSA.RSA):
585            self._signingPriKey = signingPriKey
586                   
587        else:
588            raise AttributeError("Signing private key must be a valid "
589                                  "M2Crypto.RSA.RSA type or a string")
590               
591    def _getSigningPriKey(self):
592        return self._signingPriKey
593
594    signingPriKey = property(fset=_setSigningPriKey,
595                             fget=_getSigningPriKey,
596                             doc="Private key used to sign outbound message")
597
598 
599    def _setSigningPriKeyFilePath(self, signingPriKeyFilePath):
600        """Set method for client private key file path
601       
602        signingPriKeyPwd MUST be set prior to a call to this method"""
603        if isinstance(signingPriKeyFilePath, basestring):                           
604            try:
605                # Read Private key to sign with   
606                priKeyFile = BIO.File(open(signingPriKeyFilePath)) 
607                pwdCallback = lambda *ar, **kw: self._signingPriKeyPwd                                           
608                self._signingPriKey = RSA.load_key_bio(priKeyFile, 
609                                                        callback=pwdCallback)           
610            except Exception, e:
611                raise AttributeError("Setting private key for signature: %s"%e)
612       
613        elif signingPriKeyFilePath is not None:
614            raise AttributeError("Private key file path must be a valid "
615                                 "string or None")
616       
617        self.__signingPriKeyFilePath = signingPriKeyFilePath
618       
619    signingPriKeyFilePath = property(fset=_setSigningPriKeyFilePath,
620                      doc="File path for private key used to sign message")
621
622    def __caCertIsSet(self):
623        '''Check for CA certificate set (X.509 Stack has been created)'''
624        return hasattr(self, '_caX509Stack')
625   
626    caCertIsSet = property(fget=__caCertIsSet,
627           doc='Check for CA certificate set (X.509 Stack has been created)')
628   
629    def __appendCAX509Stack(self, caCertList):
630        '''Store CA certificates in an X.509 Stack
631       
632        @param caCertList: list or tuple
633        @type caCertList: M2Crypto.X509.X509 certificate objects'''
634       
635        if not hasattr(self, '_caX509Stack'):
636            self._caX509Stack = X509Stack()
637           
638        for cert in caCertList:
639            self._caX509Stack.push(cert)
640
641
642    def __setCAX509StackFromDir(self, caCertDir):
643        '''Read CA certificates from directory and add them to the X.509
644        stack
645       
646        @param caCertDir: string
647        @type caCertDir: directory from which to read CA certificate files'''
648       
649        # Mimic OpenSSL -CApath option which expects directory of CA files
650        # of form <Hash cert subject name>.0
651        reg = re.compile('\d+\.0')
652        try:
653            caCertList = [X509CertRead(caFile) \
654                          for caFile in os.listdir(caCertDir) \
655                          if reg.match(caFile)]
656        except Exception, e:
657            raise WSSecurityError('Loading CA certificate "%s" from CA '
658                                  'directory: %s' % (caFile, str(e)))
659                   
660        # Add to stack
661        self.__appendCAX509Stack(caCertList)
662       
663    caCertDirPath = property(fset=__setCAX509StackFromDir,
664                             doc="Dir. containing CA cert.s used for "
665                                "verification")
666
667
668    def __setCAX509StackFromCertFileList(self, caCertFilePathList):
669        '''Read CA certificates from file and add them to the X.509
670        stack
671       
672        @type caCertFilePathList: list or tuple
673        @param caCertFilePathList: list of file paths for CA certificates to
674        be used to verify certificate used to sign message'''
675       
676        if not isinstance(caCertFilePathList, (list, tuple)):
677            raise WSSecurityError('Expecting a list or tuple for '
678                                  '"caCertFilePathList"')
679
680        # Mimic OpenSSL -CApath option which expects directory of CA files
681        # of form <Hash cert subject name>.0
682        try:
683            caCertList=[X509CertRead(caFile) for caFile in caCertFilePathList]
684        except Exception, e:
685            raise WSSecurityError('Loading CA certificate "%s" from file '
686                                  'list: %s' % (caFile, str(e)))
687                   
688        # Add to stack
689        self.__appendCAX509Stack(caCertList)
690       
691    caCertFilePathList = property(fset=__setCAX509StackFromCertFileList,
692                      doc="List of CA cert. files used for verification")
693               
Note: See TracBrowser for help on using the repository browser.