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

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