source: TI12-security/trunk/python/ndg.security.common/ndg/security/common/wssecurity/BaseSignatureHandler.py @ 4285

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

Refactoring of CredWallet? - first working unit tests for new version + fixes to Attribute Authority ZSI WSDL gen code interface.

Line 
1""" Base class for the WS-Security digital signature handlers - to allow
2sharing of common code
3
4NERC Data Grid Project
5"""
6__author__ = "C Byrom"
7__date__ = "18/08/08"
8__copyright__ = ""
9__license__ = \
10"""This software may be distributed under the terms of the Q Public
11License, version 1.0 or later."""
12__contact__ = "P.J.Kershaw@rl.ac.uk"
13__revision__ = '$Id: $'
14
15import re
16
17# Digest and signature/verify
18from sha import sha
19from M2Crypto import X509, BIO, RSA
20import base64
21
22# Conditional import as this is required for the encryption
23# handler
24try:
25    # For shared key encryption
26    from Crypto.Cipher import AES, DES3
27except:
28    from warnings import warn
29    warn('Crypto.Cipher not available: EncryptionHandler disabled!',
30         RuntimeWarning)
31    class AES:
32        MODE_ECB = None
33        MODE_CBC = None
34       
35    class DES3: 
36        MODE_CBC = None
37
38import os
39
40import ZSI
41from ZSI.wstools.Namespaces import DSIG, ENCRYPTION, WSU, WSA200403, \
42                                   SOAP, SCHEMA # last included for xsi
43
44from ZSI.wstools.Namespaces import OASIS as _OASIS
45                                 
46from ZSI.TC import ElementDeclaration,TypeDefinition
47from ZSI.generate.pyclass import pyclass_type
48
49from ZSI.wstools.Utility import DOMException
50from ZSI.wstools.Utility import NamespaceError, MessageInterface, ElementProxy
51
52# Canonicalization
53from ZSI.wstools.c14n import Canonicalize
54
55from xml.dom import Node
56from xml.xpath.Context import Context
57from xml import xpath
58
59# Include for re-parsing doc ready for canonicalization in sign method - see
60# associated note
61from xml.dom.ext.reader.PyExpat import Reader
62
63# Enable settings from a config file
64from ndg.security.common.wssecurity import WSSecurityConfig
65
66from ndg.security.common.X509 import X509Cert, X509CertParse, X509CertRead, \
67X509Stack, X509StackParseFromDER
68
69from datetime import datetime, timedelta
70import logging
71log = logging.getLogger(__name__)
72
73
74class _ENCRYPTION(ENCRYPTION):
75    '''Derived from ENCRYPTION class to add in extra 'tripledes-cbc' - is this
76    any different to 'des-cbc'?  ENCRYPTION class implies that it is the same
77    because it's assigned to 'BLOCK_3DES' ??'''
78    BLOCK_TRIPLEDES = "http://www.w3.org/2001/04/xmlenc#tripledes-cbc"
79
80class _WSU(WSU):
81    '''Try different utility namespace for use with WebSphere'''
82    #UTILITY = "http://schemas.xmlsoap.org/ws/2003/06/utility"
83    UTILITY = \
84"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
85
86class OASIS(_OASIS):
87    # wss4j 1.5.3
88    WSSE11 = \
89        "http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd"
90    # wss4j 1.5.1
91    #WSSE11 = "http://docs.oasis-open.org/wss/2005/xx/oasis-2005xx-wss-wssecurity-secext-1.1.xsd"
92
93
94class WSSecurityError(Exception):
95    """For WS-Security generic exceptions not covered by other exception
96    classes in this module"""
97    def __init__(self, errorMessage):
98        log.warning(errorMessage)
99        super(WSSecurityError, self).__init__(errorMessage)
100
101class InvalidCertChain(WSSecurityError):   
102    """Raised from SignatureHandler.verify if the certificate submitted to
103    verify a signature is not from a known CA"""
104   
105class VerifyError(WSSecurityError):
106    """Raised from SignatureHandler.verify if an error occurs in the signature
107    verification"""
108 
109class TimestampError(WSSecurityError):
110    """Raised from SignatureHandler._verifyTimestamp if there is a problem with
111    the created or expiry times in an input message Timestamp"""
112   
113class InvalidSignature(WSSecurityError):
114    """Raised from verify method for an invalid signature"""
115
116class SignatureError(WSSecurityError):
117    """Flag if an error occurs during signature generation"""
118
119class NoSignatureFound(WSSecurityError):
120    """Raise from SignatureHandler.verify if inbound message is not signed"""
121
122
123class BaseSignatureHandler(object):
124    """Class to handle signature and verification of signature with
125    WS-Security
126   
127    @cvar binSecTokValType: supported ValueTypes for BinarySecurityToken
128    element in WSSE header
129    @type binSecTokValType: dict
130   
131    @ivar addTimestamp: set to true to add a timestamp to outbound messages
132    @type addTimestamp: bool
133
134    @ivar applySignatureConfirmation: for servers - set this flag to enable the
135    signature value of a request to be recorded and included with a
136    SignatureConfirmation element in the response.
137    @type applySignatureConfirmation: bool
138   
139    @param b64EncSignatureValue: base 64 encoded signature value for the last
140    message verified
141    @type b64EncSignatureValue: string/None"""
142
143    _binSecTokEncType = \
144"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"
145   
146    binSecTokValType = {
147        "X509PKIPathv1": OASIS.X509TOKEN.X509PKIPathv1,
148        "X509":          OASIS.X509TOKEN.X509,
149        "X509v3":        OASIS.X509TOKEN.X509+"v3"
150    }
151
152
153    def __init__(self, cfg=None, cfgFileSection='DEFAULT',
154                 cfgClass=WSSecurityConfig, **kw):
155        '''
156        @keyword reqBinSecTokValType: set the ValueType for the
157        BinarySecurityToken added to the WSSE header for a signed message.  See
158        __setReqBinSecTokValType method and binSecTokValType class variable
159        for options.  binSecTokValType determines whether signingCert or
160        signingCertChain attributes will be used.       
161        @type binSecTokValType: string
162       
163        @keyword verifyingCert: X.509 certificate used by verify method to
164        verify a message.  This argument can be omitted if the message to
165        be verified contains the X.509 certificate in the
166        BinarySecurityToken element.  In this case, the cert read from the
167        message will be assigned to the verifyingCert attribute.
168        @type verifyingCert: M2Crypto.X509.X509 /
169        ndg.security.common.X509.X509Cert
170       
171        @keyword verifyingCertFilePath: alternative input to the above, pass
172        the file path to the certificate stored in a file
173        @type verifyingCertFilePath: string
174       
175        @keyword signingCert: certificate associated with private key used to
176        sign a message.  The sign method will add this to the
177        BinarySecurityToken element of the WSSE header.  binSecTokValType
178        attribute must be set to 'X509' or 'X509v3' ValueTyep.  As an
179        alternative, use signingCertChain - see below...
180        @type signingCert: M2Crypto.X509.X509 /
181        ndg.security.common.X509.X509Cert
182       
183        @keyword signingCertFilePath: alternative input to the above, pass
184        the file path to the certificate stored in a file
185        @type signingCertFilePath: string
186       
187        @keyword signingCertChain: pass a list of certificates constituting a
188        chain of trust from the certificate used to verifying the signature
189        backward to the CA cert.  The CA cert need not be included.  To use
190        this option, reqBinSecTokValType must be set to the 'X509PKIPathv1'
191        ValueType
192        @type signingCertChain: list or tuple
193       
194        @keyword signingPriKey: private key used to be sign method to sign
195        message
196        @type signingPriKey: M2Crypto.RSA.
197       
198        @keyword signingPriKeyFilePath: equivalent to the above but pass
199        private key from PEM file
200        @type signingPriKeyFilePath: string
201       
202        @keyword signingPriKeyPwd: password protecting private key.  Set /
203        default to None if there is no password.
204        @type signingPriKeyPwd: string or None
205       
206        @keyword caCertDirPath: establish trust for signature verification.
207        This is a directory containing CA certificates.  These are used to
208        verify the certificate used to verify the message signature.
209        @type caCertDirPath: string
210       
211        @keyword caCertFilePathList: same as above except pass in a list of
212        file paths instead of a single directory name.
213        @type caCertFilePathList: list or tuple
214       
215        @keyword addTimestamp: set to true to add a timestamp to outbound
216        messages
217        @type addTimestamp: bool
218       
219        @keyword applySignatureConfirmation: for servers - set this flag to
220        enable the signature value of a request to be recorded and included
221        with a SignatureConfirmation element in the response.
222        @type : bool
223       
224        @param refC14nInclNS: list of namespaces to include in reference
225        Canonicalization.
226        @type refC14nInclNS: list
227       
228        @param signedInfoC14nInclNS: list of namespaces to include in
229        Signed Info Canonicalization.
230        @type signedInfoC14nInclNS: list
231        '''
232        log.debug("BaseSignatureHandler.__init__ ...")
233
234        # WSSecurityConfig is the default class for reading config params but
235        # alternative derivative class may be passed in instead.
236        if not issubclass(cfgClass, WSSecurityConfig):
237            raise TypeError("%s is not a sub-class of WSSecurityConfig" % \
238                            cfgClass)
239       
240        # Read parameters from config file if set
241        if isinstance(cfg, basestring):
242            log.debug("BaseSignatureHandler.__init__: config file path input ...")
243            self.cfg = cfgClass()
244            self.cfg.read(cfg)
245        else:
246            log.debug("BaseSignatureHandler.__init__: config object input ...")
247            self.cfg = cfgClass(cfg=cfg)
248           
249        if cfg: # config object or config file path was set
250            log.debug("BaseSignatureHandler.__init__: Processing config file...")
251            self.cfg.parse(section=cfgFileSection)
252
253        # Also update config from keywords set
254        log.debug("BaseSignatureHandler.__init__: setting config from keywords...")
255        self.cfg.update(kw)
256       
257        # set default value type, if none specified in config file
258        if not self.cfg['reqBinSecTokValType']:
259            self.cfg['reqBinSecTokValType'] = "X509v3"
260           
261        self.reqBinSecTokValType = self.cfg['reqBinSecTokValType']
262
263        # Set keywords for canonicalization of SignedInfo and reference
264        # elements
265        self.refC14nKw = \
266            {'inclusive_namespaces': self.cfg['refC14nInclNS']}
267
268        self.signedInfoC14nKw = \
269            {'inclusive_namespaces': self.cfg['signedInfoC14nInclNS']}
270
271        self.verifyingCert = self.cfg['verifyingCert']
272        self.verifyingCertFilePath = self.cfg['verifyingCertFilePath']
273       
274        self.signingCert = self.cfg['signingCert']
275        self.signingCertFilePath = self.cfg['signingCertFilePath']
276
277        self.signingCertChain = self.cfg['signingCertChain']
278             
279        # MUST be set before _setSigningPriKeyFilePath / _setSigningPriKey
280        # are called
281        self.signingPriKeyPwd = self.cfg['signingPriKeyPwd']
282       
283        if self.cfg.get('signingPriKey'):
284            # Don't allow None for private key setting
285            self.signingPriKey = self.cfg['signingPriKey']
286           
287        self.signingPriKeyFilePath = self.cfg['signingPriKeyFilePath']
288       
289        # CA certificate(s) for verification of X.509 certificate used with
290        # signature.
291        if self.cfg.get('caCertDirPath'):
292            self.caCertDirPath = self.cfg['caCertDirPath']
293           
294        elif self.cfg.get('caCertFilePathList'):
295            self.caCertFilePathList = self.cfg['caCertFilePathList']
296       
297        self.addTimestamp = self.cfg['addTimestamp']
298       
299        # set default value, if none specified in config file
300        if not self.cfg['applySignatureConfirmation']:
301            self.cfg['applySignatureConfirmation'] = False
302
303        self.applySignatureConfirmation=self.cfg['applySignatureConfirmation']
304        self.b64EncSignatureValue = None
305       
306        log.debug("WSSE Config = %s" % self.cfg)
307
308               
309    def _setReqBinSecTokValType(self, value):
310        """Set ValueType attribute for BinarySecurityToken used in a request
311         
312        @type value: string
313        @param value: name space for BinarySecurityToken ValueType check
314        'binSecTokValType' class variable for supported types.  Input can be
315        shortened to binSecTokValType keyword if desired.
316        """
317        log.debug("Setting reqBinSecTokValType - to %s" %value)
318        if value in self.__class__.binSecTokValType:
319            self._reqBinSecTokValType = self.__class__.binSecTokValType[value]
320 
321        elif value in self.__class__.binSecTokValType.values():
322            self._reqBinSecTokValType = value
323        else:
324            raise WSSecurityError('Request BinarySecurityToken ValueType '
325                                  '"%s" not recognised' % value)
326           
327    def _getReqBinSecTokValType(self):
328        """
329        Get ValueType attribute for BinarySecurityToken used in a request
330        """
331        log.debug("Getting reqBinSecTokValType value")
332        if hasattr(self, '_reqBinSecTokValType'):
333            return self._reqBinSecTokValType
334        else:
335            return ""
336       
337    reqBinSecTokValType = property(fset=_setReqBinSecTokValType,
338                                   fget=_getReqBinSecTokValType,
339         doc="ValueType attribute for BinarySecurityToken used in request")
340       
341
342    def __checkC14nKw(self, kw):
343        """Check keywords for canonicalization in signing process - generic
344        method for setting keywords for reference element and SignedInfo
345        element c14n
346       
347        @type kw: dict
348        @param kw: keyword used with ZSI.wstools.Utility.Canonicalization"""
349       
350        # Check for dict/None - Set to None in order to use inclusive
351        # canonicalization
352        if kw is not None and not isinstance(kw, dict):
353            # Otherwise keywords must be a dictionary
354            raise AttributeError, \
355                "Expecting dictionary type for reference c14n keywords"
356               
357        elif kw.get('inclusive_namespaces') and \
358             not isinstance(kw['inclusive_namespaces'], list) and \
359             not isinstance(kw['inclusive_namespaces'], tuple):
360            raise AttributeError('Expecting list or tuple of prefix names for '
361                                 '"%s" keyword' % 'inclusive_namespaces')
362       
363               
364    def _setRefC14nKw(self, kw):
365        """Set keywords for canonicalization of reference elements in the
366        signing process"""
367        self.__checkC14nKw(kw)                   
368        self._refC14nKw = kw
369       
370    def _getRefC14nKw(self):
371        if hasattr(self, '_refC14nKw'):
372            return self._refC14nKw
373        else:
374            return {}
375       
376    refC14nKw = property(fset=_setRefC14nKw,
377                         fget=_getRefC14nKw,
378                         doc="Keywords for c14n of reference elements")
379       
380               
381    def _setSignedInfoC14nKw(self, kw):
382        """Set keywords for canonicalization of SignedInfo element in the
383        signing process"""
384        self.__checkC14nKw(kw)                   
385        self._signedInfoC14nKw = kw
386       
387    def _getSignedInfoC14nKw(self):
388        if hasattr(self, '_signedInfoC14nKw'):
389            return self._signedInfoC14nKw
390        else:
391            return {}
392       
393    signedInfoC14nKw = property(fset=_setSignedInfoC14nKw,
394                                fget=_getSignedInfoC14nKw,
395                                doc="Keywords for c14n of SignedInfo element")
396
397
398    def __refC14nIsExcl(self):
399        return isinstance(self._refC14nKw, dict) and \
400               isinstance(self._refC14nKw.get('inclusive_namespaces'), list) and \
401               len(self._refC14nKw['inclusive_namespaces']) > 0
402               
403    refC14nIsExcl = property(fget=__refC14nIsExcl,
404    doc="Return True/False c14n for reference elements set to exclusive type")
405
406     
407    def __signedInfoC14nIsExcl(self):
408        return isinstance(self._signedInfoC14nKw, dict) and \
409        isinstance(self._signedInfoC14nKw.get('inclusive_namespaces'), list) and \
410        len(self._signedInfoC14nKw['inclusive_namespaces']) > 0
411       
412    signedInfoC14nIsExcl = property(fget=__signedInfoC14nIsExcl,
413                                    doc="Return True/False c14n for "
414                                    "SignedInfo element set to exclusive type")
415   
416   
417    def __setCert(self, cert):
418        """filter and convert input cert to signing verifying cert set
419        property methods.  For signingCert, set to None if it is not to be
420        included in the SOAP header.  For verifyingCert, set to None if this
421        cert can be expected to be retrieved from the SOAP header of the
422        message to be verified
423       
424        @type: ndg.security.common.X509.X509Cert / M2Crypto.X509.X509 /
425        string or None
426        @param cert: X.509 certificate. 
427       
428        @rtype ndg.security.common.X509.X509Cert
429        @return X.509 certificate object"""
430       
431        if not cert or isinstance(cert, X509Cert):
432            # ndg.security.common.X509.X509Cert type / None
433            return cert
434           
435        elif isinstance(cert, X509.X509):
436            # M2Crypto.X509.X509 type
437            return X509Cert(m2CryptoX509=cert)
438           
439        elif isinstance(cert, basestring):
440            return X509CertParse(cert)
441       
442        else:
443            raise AttributeError, "X.509 Cert. must be type: " + \
444                "ndg.security.common.X509.X509Cert, M2Crypto.X509.X509 or " +\
445                "a base64 encoded string"
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 cert object corresponding to cert used with
491        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 Cert. to include signature")
509
510 
511    def _setSigningCertFilePath(self, signingCertFilePath):
512        "Set signature X.509 cert property method"
513       
514        if isinstance(signingCertFilePath, basestring):
515            self._signingCert = X509CertRead(signingCertFilePath)
516           
517        elif signingCertFilePath is not None:
518            raise AttributeError(
519                "Signature X.509 cert. file path must 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 to verify msg.")
556
557 
558    def _setSigningPriKeyPwd(self, signingPriKeyPwd):
559        "Set method for private key file password used to sign message"
560        if signingPriKeyPwd is not None and \
561           not isinstance(signingPriKeyPwd, basestring):
562            raise AttributeError, \
563                "Signing private key password must be None or a valid string"
564       
565        self._signingPriKeyPwd = signingPriKeyPwd
566
567    def _getSigningPriKeyPwd(self):
568        if hasattr(self, '_signingPriKeyPwd'):
569            return self._signingPriKeyPwd
570        else:
571            return ""
572       
573    signingPriKeyPwd = property(fset=_setSigningPriKeyPwd,
574                                fget=_getSigningPriKeyPwd,
575             doc="Password protecting private key file used to sign message")
576
577 
578    def _setSigningPriKey(self, signingPriKey):
579        """Set method for client private key
580       
581        Nb. if input is a string, signingPriKeyPwd will need to be set if
582        the key is password protected.
583       
584        @type signingPriKey: M2Crypto.RSA.RSA / string
585        @param signingPriKey: private key used to sign message"""
586       
587        if isinstance(signingPriKey, basestring):
588            pwdCallback = lambda *ar, **kw: self._signingPriKeyPwd
589            self._signingPriKey = RSA.load_key_string(signingPriKey,
590                                                       callback=pwdCallback)
591
592        elif isinstance(signingPriKey, RSA.RSA):
593            self._signingPriKey = signingPriKey
594                   
595        else:
596            raise AttributeError("Signing private key must be a valid "
597                                  "M2Crypto.RSA.RSA type or a string")
598               
599    def _getSigningPriKey(self):
600        return self._signingPriKey
601
602    signingPriKey = property(fset=_setSigningPriKey,
603                             fget=_getSigningPriKey,
604                             doc="Private key used to sign outbound message")
605
606 
607    def _setSigningPriKeyFilePath(self, signingPriKeyFilePath):
608        """Set method for client private key file path
609       
610        signingPriKeyPwd MUST be set prior to a call to this method"""
611        if isinstance(signingPriKeyFilePath, basestring):                           
612            try:
613                # Read Private key to sign with   
614                priKeyFile = BIO.File(open(signingPriKeyFilePath)) 
615                pwdCallback = lambda *ar, **kw: self._signingPriKeyPwd                                           
616                self._signingPriKey = RSA.load_key_bio(priKeyFile, 
617                                                        callback=pwdCallback)           
618            except Exception, e:
619                raise AttributeError("Setting private key for signature: %s"%e)
620       
621        elif signingPriKeyFilePath is not None:
622            raise AttributeError("Private key file path must be a valid "
623                                 "string or None")
624       
625        self.__signingPriKeyFilePath = signingPriKeyFilePath
626       
627    signingPriKeyFilePath = property(fset=_setSigningPriKeyFilePath,
628                      doc="File path for private key used to sign message")
629
630    def __caCertIsSet(self):
631        '''Check for CA certificate set (X.509 Stack has been created)'''
632        return hasattr(self, '_caX509Stack')
633   
634    caCertIsSet = property(fget=__caCertIsSet,
635           doc='Check for CA certificate set (X.509 Stack has been created)')
636   
637    def __appendCAX509Stack(self, caCertList):
638        '''Store CA certificates in an X.509 Stack
639       
640        @param caCertList: list or tuple
641        @type caCertList: M2Crypto.X509.X509 certificate objects'''
642       
643        if not hasattr(self, '_caX509Stack'):
644            self._caX509Stack = X509Stack()
645           
646        for cert in caCertList:
647            self._caX509Stack.push(cert)
648
649
650    def __setCAX509StackFromDir(self, caCertDir):
651        '''Read CA certificates from directory and add them to the X.509
652        stack
653       
654        @param caCertDir: string
655        @type caCertDir: directory from which to read CA certificate files'''
656       
657        # Mimic OpenSSL -CApath option which expects directory of CA files
658        # of form <Hash cert subject name>.0
659        reg = re.compile('\d+\.0')
660        try:
661            caCertList = [X509CertRead(caFile) \
662                          for caFile in os.listdir(caCertDir) \
663                          if reg.match(caFile)]
664        except Exception, e:
665            raise WSSecurityError('Loading CA certificate "%s" from CA '
666                                  'directory: %s' % (caFile, str(e)))
667                   
668        # Add to stack
669        self.__appendCAX509Stack(caCertList)
670       
671    caCertDirPath = property(fset=__setCAX509StackFromDir,
672                             doc="Dir. containing CA cert.s used for "
673                                "verification")
674
675
676    def __setCAX509StackFromCertFileList(self, caCertFilePathList):
677        '''Read CA certificates from file and add them to the X.509
678        stack
679       
680        @type caCertFilePathList: list or tuple
681        @param caCertFilePathList: list of file paths for CA certificates to
682        be used to verify certificate used to sign message'''
683       
684        if not isinstance(caCertFilePathList, (list, tuple)):
685            raise WSSecurityError('Expecting a list or tuple for '
686                                  '"caCertFilePathList"')
687
688        # Mimic OpenSSL -CApath option which expects directory of CA files
689        # of form <Hash cert subject name>.0
690        try:
691            caCertList = [X509CertRead(caFile) \
692                          for caFile in caCertFilePathList]
693        except Exception, e:
694            raise WSSecurityError('Loading CA certificate "%s" from file '
695                                  'list: %s' % (caFile, str(e)))
696                   
697        # Add to stack
698        self.__appendCAX509Stack(caCertList)
699       
700    caCertFilePathList = property(fset=__setCAX509StackFromCertFileList,
701                      doc="List of CA cert. files used for verification")
702               
Note: See TracBrowser for help on using the repository browser.