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

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

Added a Policy Information Point to encapsulate subject attribute retrieval.

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