Changeset 1953


Ignore:
Timestamp:
04/01/07 16:19:03 (13 years ago)
Author:
pjkersha
Message:

python/ndg.security.test/ndg/security/test/XMLSecDoc/xmlSecDocTest.cfg: revised test file outputs to
distinguish signed and unsigned output

python/ndg.security.test/ndg/security/test/XMLSecDoc/xmlSecDocTest.py and
python/ndg.security.common/ndg/security/common/XMLSec.py: working enveloped signature but requires verification
against equivalent verify method and independent pyXMLSec code.

Location:
TI12-security/trunk/python
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/XMLSec.py

    r1947 r1953  
    11"""NDG XML Security - Encryption and Digital Signature 
    22 
    3 Nerc Data Grid Project 
    4  
    5 P J Kershaw 05/04/05 
     3NERC Data Grid Project 
     4 
     5@author P J Kershaw 05/04/05 
    66 
    77P J Kershaw 03/01/07: Re-write to use M2Crypto, ZSI and DOM instead of  
    88pyXMLSec 
    99 
    10 This software may be distributed under the terms of the Q Public License, 
    11 version 1.0 or later.""" 
    12  
    13 cvsID = '$Id$' 
     10@copyright (C) 2007 CCLRC & NERC 
     11 
     12@license This software may be distributed under the terms of the Q Public  
     13License, version 1.0 or later.""" 
     14 
     15reposID = '$Id$' 
    1416 
    1517 
     
    2931# associated note 
    3032from xml.dom.ext.reader.PyExpat import Reader 
     33from Ft.Xml.Domlette import NonvalidatingReader 
    3134 
    3235# Digest and signature/verify 
     
    4144from xml import xpath 
    4245 
    43 from ZSI.wstools.Namespaces import DSIG 
     46from ZSI.wstools.Namespaces import DSIG, XMLNS 
     47 
     48     
     49def getElements(node, nameList): 
     50    '''DOM Helper function for getting child elements from a given node''' 
     51    # Avoid sub-string matches 
     52    nameList = isinstance(nameList, basestring) and [nameList] or nameList 
     53    return [n for n in node.childNodes if str(n.localName) in nameList] 
    4454 
    4555 
    4656class XMLSecDocError(Exception): 
    4757    """Exception handling for NDG XML Security class.""" 
    48      
    49     def __init__(self, msg): 
    50         self.__msg = msg 
    51           
    52     def __str__(self): 
    53         return self.__msg 
    54  
    55  
    56 class XMLSecDocOld(object): 
     58 
     59class SignError(Exception):   
     60    """Raised form sign method if an error occurs generating the signature""" 
     61      
     62class VerifyError(Exception): 
     63    """Raised from verify method if an error occurs""" 
     64    
     65class InvalidSignature(Exception): 
     66    """Raised from verify method for an invalid signature""" 
     67 
     68 
     69#_____________________________________________________________________________ 
     70class XMLSecDoc(object): 
    5771    """Implements XML Signature and XML Encryption for a Document.""" 
    5872 
    59     #__metaclass__ = XMLSecDocMetaClass 
    60      
    6173    def __init__(self, 
    6274                 filePath=None, 
    6375                 signingKeyFilePath=None, 
     76                 certFilePathList=None, 
    6477                 encrCertFilePath=None, 
    65                  encrPriKeyFilePath=None, 
    66                  certFilePathList=None): 
    67  
    68         """Initialisation - 
    69              
    70         filePath:            file path for document 
    71         signingKeyFilePath:  file path for private key used in signature 
    72         encrPriKeyFilePath:     file path for private key used to decrypt 
    73                              previously encrypted document 
    74         certFilePathList:    list of public keys used for checking signature 
    75                              of a document or for encrypting a document""" 
    76  
    77         self.__filePath = None 
    78         self.__signingKeyFilePath = None 
    79         self.__encrCertFilePath = None 
    80         self.__encrPriKeyFilePath = None 
    81         self.__certFilePathList = None 
    82  
    83  
    84         if filePath is not None: 
    85             if not isinstance(filePath, basestring): 
    86                 raise XMLSecDocError("Input key file path is %s" % \ 
    87                                      type(filePath) + \ 
    88                                      ": string type expected") 
    89  
    90             self.__filePath = filePath 
    91  
    92  
    93         # Private key file to be used to sign the document 
    94         if signingKeyFilePath is not None: 
    95             self.__setSigningKeyFilePath(signingKeyFilePath) 
    96  
    97  
    98         # Public key file to be used to encrypt document 
    99         if encrCertFilePath is not None: 
    100             self.__setEncrCertFilePath(encrCertFilePath) 
    101  
    102  
    103         # Private key file to be used to decrypt document 
    104         if encrPriKeyFilePath is not None: 
    105             self.__setEncrPriKeyFilePath(encrPriKeyFilePath) 
    106  
    107  
    108         # This may be either of: 
    109         # 1) Certificate file to be used for signing document 
    110         # 2) list of files one of which is the certificate used to sign the 
    111         # document being checked 
    112         if certFilePathList is not None: 
    113             self.__setCertFilePathList(certFilePathList) 
    114  
    115  
    116         # Keep track of libxml2/libxmlsec variables which need explicit 
    117         # freeing 
    118         self.__libxml2Doc = None 
    119         self.__bLibxml2DocFreed = False 
    120              
    121         self.__libxml2Ctxt = None 
    122         self.__bLibxml2CtxtFreed = False 
    123  
    124         self.__dSigCtxt = None 
    125         self.__bDSigCtxtFreed = False 
    126  
    127         self.__encCtxt = None 
    128         self.__bEncCtxtFreed = False 
    129  
    130         self.__keysMngr = None 
    131         self.__bKeysMngrFreed = False 
    132  
    133         self.__keysStore = None 
    134         self.__bKeysStoreFreed = False 
    135   
    136         self.__initLibs() 
    137          
    138          
    139     #_________________________________________________________________________ 
    140     def __initLibs(self): 
    141  
    142         # Initialise libxml2 library 
    143         libxml2.initParser() 
    144         libxml2.substituteEntitiesDefault(1) 
    145          
    146         # Init xmlsec library 
    147         if xmlsec.init() < 0: 
    148             raise XMLSecDocError("xmlsec initialization failed.") 
    149  
    150          
    151         # Check loaded library version 
    152         if xmlsec.checkVersion() != 1: 
    153             raise XMLSecDocError("xmlsec library version is not compatible.") 
    154  
    155  
    156         # Init crypto library 
    157         if xmlsec.cryptoAppInit(None) < 0: 
    158             raise XMLSecDocError("Crypto initialization failed.") 
    159  
    160          
    161         # Init xmlsec-crypto library 
    162         if xmlsec.cryptoInit() < 0: 
    163             raise XMLSecDocError("xmlsec-crypto initialization failed.") 
    164  
    165  
    166     #_________________________________________________________________________        
    167     def __shutdownLibs(self): 
    168  
    169         try: 
    170             # Shutdown xmlsec-crypto library 
    171             xmlsec.cryptoShutdown() 
    172      
    173             # Shutdown crypto library 
    174             xmlsec.cryptoAppShutdown() 
    175      
    176             # Shutdown xmlsec library 
    177             # Fudge - comment out to avoid error messages but may cause 
    178             # mem leaks?? 
    179             # 
    180             # P J Kershaw 24/03/06 
    181             #xmlsec.shutdown() 
    182      
    183             # Shutdown LibXML2 
    184             libxml2.cleanupParser() 
    185              
    186         except Exception, e: 
    187             raise XMLSecDocError("Cleaning up xmlsec: %s" % e) 
    188  
    189  
    190     def __str__(self): 
    191         """String representation of doc - only applies if doc had been read 
    192         or parsed""" 
    193         if self.__libxml2Doc: 
    194             return self.asString() 
    195         else: 
    196             return "" 
    197      
    198      
    199     def __del__(self): 
    200         """Ensure cleanup of libxml2 and xmlsec memory allocated""" 
    201         self.__cleanup() 
    202         self.__shutdownLibs() 
    203          
    204  
    205     #_________________________________________________________________________ 
    206     def __libxml2ParseDoc(self, xmlTxt): 
    207         """Wrapper for libxml2.parseDoc() - enables inclusion of flag to 
    208         indicate to __cleanup method if libxml2.freeDoc() needs to be 
    209         called.""" 
    210          
    211         if self.__libxml2Doc is not None and not self.__bLibxml2DocFreed: 
    212             self.__libxml2Doc.freeDoc() 
    213  
    214         # Create new doc and reset flag 
    215         try: 
    216             self.__libxml2Doc = libxml2.parseDoc(xmlTxt) 
    217  
    218         except Exception, excep: 
    219             raise XMLSecDocError("Error parsing document: %s" % str(excep)) 
    220          
    221         if self.__libxml2Doc is None or \ 
    222            self.__libxml2Doc.getRootElement() is None: 
    223             raise XMLSecDocError("Error parsing Attribute Certificate") 
    224              
    225         self.__bLibxml2DocFreed = False 
    226           
    227  
    228     #_________________________________________________________________________ 
    229     def __libxml2ParseFile(self): 
    230  
    231         """Wrapper for libxml2.parseFile() - enables inclusion of flag to 
    232         indicate to __cleanup method if libxml2.freeDoc() needs to be 
    233         called.""" 
    234          
    235         if self.__libxml2Doc is not None and not self.__bLibxml2DocFreed: 
    236             self.__libxml2Doc.freeDoc() 
    237  
    238         # Create new doc and reset flag 
    239         try: 
    240             self.__libxml2Doc = libxml2.parseFile(self.__filePath) 
    241  
    242         except Exception, excep: 
    243             raise XMLSecDocError("Error parsing file: %s" % str(excep)) 
    244  
    245          
    246         if self.__libxml2Doc is None or \ 
    247            self.__libxml2Doc.getRootElement() is None: 
    248             raise XMLSecDocError(\ 
    249                 "Error parsing Attribute Certificate \"%s\"" % self.__filePath) 
    250              
    251         self.__bLibxml2DocFreed = False 
    252      
    253         
    254     #_________________________________________________________________________ 
    255     def __libxml2XPathNewContext(self): 
    256  
    257         """Wrapper for libxml2.parseDocxpathNewContext() - enables inclusion 
    258         of flag to indicate to __cleanup method if libxml2.xpathFreeContext() 
    259         needs to be called.""" 
    260  
    261         if self.__libxml2Doc is None: 
    262             raise XMLSecDocError(\ 
    263                 "self.__libxml2ParseDoc() must be called first") 
    264          
    265         if self.__libxml2Ctxt is not None and not self.__bLibxml2CtxtFreed: 
    266             self.__libxml2Ctxt.xpathFreeContext() 
    267  
    268         # Create new context and reset flag 
    269         self.__libxml2Ctxt = self.__libxml2Doc.xpathNewContext() 
    270         if self.__libxml2Ctxt is None: 
    271             raise XMLSecDocError("Error creating XPath context for \"%s\"" % \ 
    272                                   self.__filePath) 
    273  
    274         self.__bLibxml2CtxtFreed = False 
    275  
    276  
    277     #_________________________________________________________________________ 
    278     def __xmlsecDSigCtx(self, keysMngr=None):     
    279         """Wrapper for xmlsec.DSigCtx() - enables inclusion 
    280         of flag to indicate to __cleanup method if xmlsec.DSigCtx.destroy() 
    281         needs to be called.""" 
    282  
    283         # Check memory from any previous object has been released 
    284         if self.__dSigCtxt is not None and not self.__bDSigCtxtFreed: 
    285             self.__dSigCtxt.destroy() 
    286         
    287         self.__dSigCtxt = xmlsec.DSigCtx(keysMngr) 
    288         if self.__dSigCtxt is None: 
    289             raise XMLSecDocError("Error creating signature context") 
    290  
    291         self.__bDSigCtxtFreed = False 
    292  
    293  
    294     #_________________________________________________________________________ 
    295     def __xmlsecEncCtx(self, keysMngr=None):     
    296         """Wrapper for xmlsec.EncCtx() - enables inclusion 
    297         of flag to indicate to __cleanup method if xmlsec.EncCtx.destroy() 
    298         needs to be called.""" 
    299  
    300         # Check memory from any previous object has been released 
    301         if self.__encCtxt is not None and not self.__bEncCtxtFreed: 
    302             self.__encCtxt.destroy() 
    303         
    304  
    305         self.__encCtxt = xmlsec.EncCtx(keysMngr) 
    306         if self.__encCtxt is None: 
    307             raise XMLSecDocError("Error creating encryption context") 
    308  
    309         self.__bEncCtxtFreed = False 
    310  
    311  
    312     #_________________________________________________________________________ 
    313     def __xmlsecKeysMngr(self): 
    314         """Wrapper for xmlsec.KeysMngr() - enables inclusion 
    315         of flag to indicate to __cleanup method if xmlsec.KeysMngr.destroy() 
    316         needs to be called.""" 
    317  
    318         # Check memory from any previous object has been released 
    319         if self.__keysMngr is not None and not self.__bKeysMngrFreed: 
    320             self.__keysMngr.destroy() 
    321      
    322         self.__keysMngr = xmlsec.KeysMngr() 
    323         if self.__keysMngr is None: 
    324             raise XMLSecDocError("Failed to create keys manager.") 
    325  
    326         self.__bKeysMngrFreed = False 
    327  
    328  
    329     #_________________________________________________________________________      
    330     def __cleanup(self): 
    331         """Private method for cleanup associated with libxml2/xmlsec""" 
    332  
    333         # libxml2 doc created for parsing an existing Attribut Certificate/ 
    334         # signing a new certificate 
    335         if self.__libxml2Doc is not None and not self.__bLibxml2DocFreed: 
    336             self.__libxml2Doc.freeDoc() 
    337             self.__bLibxml2DocFreed = True 
    338  
    339         # libxml2 XPath Context associated with libxml2 doc object 
    340         if self.__libxml2Ctxt is not None and not self.__bLibxml2CtxtFreed: 
    341             self.__libxml2Ctxt.xpathFreeContext() 
    342             self.__bLibxml2CtxtFreed = True 
    343  
    344         # xmlsec Digital Signature object 
    345         if self.__dSigCtxt is not None and not self.__bDSigCtxtFreed: 
    346             self.__dSigCtxt.destroy() 
    347             self.__bDSigCtxtFreed = True 
    348  
    349         # xmlsec Encryption Context object 
    350         if self.__encCtxt is not None and not self.__bEncCtxtFreed: 
    351             self.__encCtxt.destroy() 
    352             self.__bEncCtxtFreed = True 
    353          
    354         # xmlsec Keys Manager 
    355         if self.__keysMngr is not None and not self.__bKeysMngrFreed: 
    356             self.__keysMngr.destroy() 
    357             self.__bKeysMngrFreed = True 
    358   
    359  
    360  
    361  
    362     def __getFilePath(self): 
    363         """Get file path for file to be signed/encrypted.""" 
    364         return self.__filePath 
    365  
    366  
    367     def __setFilePath(self, filePath): 
    368         """Set file path for file to be signed/encrypted.""" 
    369          
    370         if filePath is None or not isinstance(filePath, basestring):             
    371             raise XMLSecDocError("Document file path must be a valid string") 
    372          
    373         self.__filePath = filePath 
    374  
    375  
    376     def __delFilePath(self): 
    377         """Prevent file path being deleted.""" 
    378         raise AttributeError("\"filePath\" cannot be deleted") 
    379   
    380    
    381     # Publish attribute as read/write 
    382     filePath = property(fget=__getFilePath, 
    383                         fset=__setFilePath, 
    384                         fdel=__delFilePath, 
    385                         doc="File Path for XML document to apply security to") 
    386  
    387  
    388     #_________________________________________________________________________ 
    389     def __setCertFilePathList(self, filePath): 
    390         """File path for certificate used to sign document /  
    391         list of certificates used to check the signature of a document""" 
    392          
    393         if isinstance(filePath, basestring):         
    394             self.__certFilePathList = [filePath] 
    395  
    396         elif isinstance(filePath, list): 
    397             self.__certFilePathList = filePath 
    398                                              
    399         elif isinstance(filePath, tuple): 
    400             self.__certFilePathList = list(filePath) 
    401  
    402         else: 
    403             raise XMLSecDocError(\ 
    404             "Signing Certificate file path must be a valid string or list") 
    405   
    406    
    407     # Publish attribute as write only 
    408     certFilePathList = property(fset=__setCertFilePathList, 
    409         doc="File Path of certificate used to sign document / " + \ 
    410             "list of certificates used to check the signature of a doc") 
    411  
    412  
    413     #_________________________________________________________________________ 
    414     def __setSigningKeyFilePath(self, filePath): 
    415         """Set file path for certificate private key used to sign doc.""" 
    416          
    417         if filePath is None or not isinstance(filePath, basestring):             
    418             raise XMLSecDocError(\ 
    419                 "Certificate key file path must be a valid string") 
    420          
    421         self.__signingKeyFilePath = filePath 
    422  
    423     # Publish attribute as write only 
    424     signingKeyFilePath = property(fset=__setSigningKeyFilePath, 
    425                 doc="file path for certificate private key used to sign doc") 
    426  
    427  
    428  
    429     #_________________________________________________________________________ 
    430     def __setEncrCertFilePath(self, filePath): 
    431         """Set file path for certificate publiv key used to decrypt doc.""" 
    432          
    433         if filePath is None or not isinstance(filePath, basestring):             
    434             raise XMLSecDocError(\ 
    435                 "Certificate key file path must be a valid string") 
    436  
    437         self.__encrCertFilePath = filePath 
    438  
    439     # Publish attribute as write only 
    440     encrCertFilePath = property(fset=__setEncrCertFilePath, 
    441         doc="file path for certificate publiv key used to decrypt doc") 
    442  
    443  
    444     #_________________________________________________________________________ 
    445     def __setEncrPriKeyFilePath(self, filePath): 
    446         """Set file path for certificate private key used to decrypt doc.""" 
    447          
    448         if filePath is None or not isinstance(filePath, basestring):             
    449             raise XMLSecDocError(\ 
    450                 "Certificate key file path must be a valid string") 
    451          
    452         self.__encrPriKeyFilePath = filePath 
    453  
    454     # Publish attribute as write only 
    455     encrPriKeyFilePath = property(fset=__setEncrPriKeyFilePath, 
    456         doc="file path for certificate private key used to decrypt doc") 
    457  
    458  
    459     #_________________________________________________________________________ 
    460     def asString(self, filePath=None, stripXMLhdr=False): 
    461         """Return certificate file content as a string""" 
    462          
    463         # Check libxml2.xmlDoc object has been instantiated - if not call 
    464         # read method 
    465         if self.__libxml2Doc is None: 
    466             if filePath is None: 
    467                 raise XMLSecDocError(\ 
    468                     "A file must be parsed first for asString()") 
    469                      
    470             self.read(filePath) 
    471  
    472         try: 
    473             # Make a buffer 
    474             f = StringIO() 
    475             buf = libxml2.createOutputBuffer(f, 'UTF-8') 
    476  
    477             # Write to buffer 
    478             self.__libxml2Doc.saveFormatFileTo(buf, 'UTF-8', 0) 
    479  
    480  
    481             # Return string content 
    482             if stripXMLhdr: 
    483                 return re.sub("<\?xml.*>\s", "", f.getvalue()) 
    484             else: 
    485                 return f.getvalue() 
    486  
    487         except Exception, e: 
    488             raise XMLSecDocError("Error outputting document as a string:" % \ 
    489                                  e) 
    490  
    491  
    492     #_________________________________________________________________________ 
    493     def parse(self, xmlTxt): 
    494  
    495         """Parse string containing XML into a libxml2 document to allow 
    496         signature validation""" 
    497  
    498         self.__libxml2ParseDoc(xmlTxt) 
    499  
    500  
    501     #_________________________________________________________________________ 
    502     def read(self, filePath=None): 
    503  
    504         """Read XML into a libxml2 document to allow signature validation""" 
    505  
    506         # Check for file path passed as input argument otherwise use member 
    507         # variable 
    508         if filePath is not None: 
    509             self.__filePath = filePath 
    510  
    511         self.__libxml2ParseFile() 
    512  
    513  
    514     #_________________________________________________________________________ 
    515     def write(self, filePath=None, bSign=False, xmlTxt=None, **signKeys): 
    516  
    517         """Write XML document applying digital signature 
    518  
    519         filePath:               file path for XML output 
    520                              
    521         bSign:                  flag defaults to False to NOT sign the 
    522                                 document.  Explicitly set to True to sign 
    523                                 the new certificate using the private key 
    524                                 and certificate. 
    525  
    526         xmlTxt:                 string containing formatted xml text for 
    527                                 signing.  If no text is provided, the method 
    528                                 createXML() is called to return the text. 
    529                                 Derived classes should implement this method. 
    530  
    531         Keyword arguments required by XMLSecDoc.sign(): 
    532          
    533         signingKeyFilePath:     file path to private key file of Attribute 
    534                                 Authority - may also be set in  __init__ 
    535  
    536         signingKeyPwd:          password for signing key file. 
    537  
    538         certFilePathList:       file paths to certificate files 
    539                                 """ 
    540  
    541          
    542         if filePath is not None: 
    543             self.setFilePath(filePath) 
    544  
    545          
    546         # Set up libxml2 object from string containing XML for writing 
    547         if xmlTxt is None: xmlTxt = self.createXML() 
    548  
    549          
    550         # Apply digital signature of Attribute Authority 
    551         if bSign: self.sign(xmlTxt=xmlTxt, **signKeys) 
    552  
    553  
    554         # Ensure libxml2 doc has been created for document to be written 
    555         #  A valid one should be present if sign() was called above 
    556         if self.__libxml2Doc is None: self.__libxml2ParseDoc(xmlTxt) 
    557  
    558              
    559         # Updated content is held in libxml2 doc instance.  Use this to 
    560         # write new certificate to file 
    561         self.__libxml2Doc.saveFormatFile(self.__filePath, True) 
    562  
    563  
    564     #_________________________________________________________________________ 
    565     def createXML(self): 
    566  
    567         """VIRTUAL method - derived class should implement - 
    568         Create text for output and return as a string""" 
    569          
    570         raise XMLSecDocError(\ 
    571                     "Virtual function: Derived class should implement.") 
    572  
    573         return None 
    574  
    575  
    576     #_________________________________________________________________________ 
    577     def sign(self, 
    578              xmlTxt=None, 
    579              signingKeyFilePath=None, 
    580              signingKeyPwd=None, 
    581              certFilePathList=None, 
    582                  inclX509Cert=True, 
    583              inclX509SubjName=True, 
    584                  inclX509IssSerial=True, 
    585              rtnAsString=False): 
    586         """Sign XML document using an X.509 certificate private key 
    587  
    588         xmlTxt:                 string buffer containing xml to be signed. If 
    589                                 not provided, calls XMLSecDoc.createXML(). 
    590                                 This is a virtual method so must be defined 
    591                                 in a derived class. 
    592                              
    593         signingKeyFilePath:     file path to private key file used to sign 
    594                                 the document 
    595  
    596         signingKeyPwd:          password for signing key file. 
    597          
    598         certFilePathList:       include certificate of signer  
    599             inclX509Cert:                   include MIME encoded content of X.509  
    600                                                 certificate that will sign the document 
    601         inclX509SubjName:           include subject name of signing X.509  
    602                                                 certificate. 
    603             inclX509IssSerial:      include issuer name and serial inumber in 
    604                                                 signature 
    605                                          
    606         rtnAsString:            This method returns None by default.  Set to  
    607                                 True to override and return the signed 
    608                                 result instead as a string.""" 
    609  
    610         # Create string buffer from virtual function if not passed 
    611         # as input argument - derived class must implement  
    612         if xmlTxt is None: 
    613             xmlTxt = self.createXML() 
    614  
    615              
    616         # Set private key file 
    617         if signingKeyFilePath is not None: 
    618             self.__setSigningKeyFilePath(signingKeyFilePath)             
    619  
    620  
    621         # Public certificate file  
    622         if certFilePathList is not None: 
    623             self.__setCertFilePathList(certFilePathList) 
    624  
    625  
    626         # Check files for read access 
    627         try: 
    628             if not os.access(self.__signingKeyFilePath, os.R_OK): 
    629                 raise XMLSecDocError("not found or no read access") 
    630                                       
    631         except Exception, e: 
    632             raise XMLSecDocError(\ 
    633                 "Private key file path is not valid: \"%s\": %s" % \ 
    634                 (self.__signingKeyFilePath, str(e))) 
    635  
    636          
    637         try: 
    638             if not os.access(self.__certFilePathList[0], os.R_OK): 
    639                 raise XMLSecDocError("not found or no read access") 
    640              
    641         except Exception, e: 
    642             raise XMLSecDocError(\ 
    643                 "Signing certificate file path is not valid: \"%s\": %s" % \ 
    644                 (self.__certFilePathList[0], str(e))) 
    645  
    646  
    647         # Create libxml2 doc instance 
    648         self.__libxml2ParseDoc(xmlTxt)             
    649  
    650  
    651         # Create signature template for RSA-SHA1 enveloped signature 
    652         sigNode = xmlsec.TmplSignature(self.__libxml2Doc, 
    653                                        xmlsec.transformExclC14NId(), 
    654                                        xmlsec.transformRsaSha1Id(), 
    655                                        None) 
    656         if sigNode is None: 
    657             raise XMLSecDocError("Error creating signature template") 
    658  
    659          
    660         # Add <dsig:Signature/> node to the doc 
    661         self.__libxml2Doc.getRootElement().addChild(sigNode) 
    662  
    663  
    664         # Add reference 
    665         refNode = sigNode.addReference(xmlsec.transformSha1Id(), 
    666                                        None, None, None) 
    667         if refNode is None: 
    668             raise XMLSecDocError( 
    669                 "Error adding reference to signature template") 
    670  
    671  
    672         # Add enveloped transform 
    673         if refNode.addTransform(xmlsec.transformEnvelopedId()) is None: 
    674             raise XMLSecDocError(\ 
    675                 "Error adding enveloped transform to reference") 
    676  
    677   
    678         # Add <dsig:KeyInfo/> and <dsig:X509Data/> 
    679         keyInfoNode = sigNode.ensureKeyInfo(None) 
    680         if keyInfoNode is None: 
    681             raise XMLSecDocError("Error adding key info") 
    682  
    683  
    684         x509DataNode = keyInfoNode.addX509Data() 
    685         if x509DataNode is None: 
    686             raise XMLSecDocError("Error adding X509Data node") 
    687  
    688  
    689         # Add extra X509Data info 
    690         if inclX509Cert: 
    691             if xmlsec.addChild(x509DataNode, 
    692                                            xmlsec.NodeX509Certificate) is None: 
    693                 raise XMLSecDocError("Error adding %s node" % \ 
    694                                      xmlsec.NodeX509Certificate) 
    695  
    696         if inclX509SubjName: 
    697             if xmlsec.addChild(x509DataNode, 
    698                                            xmlsec.NodeX509SubjectName) is None: 
    699                 raise XMLSecDocError("Error adding %s node" % \ 
    700                                      xmlsec.NodeX509SubjectName) 
    701  
    702         if inclX509IssSerial: 
    703             if xmlsec.addChild(x509DataNode, 
    704                                            xmlsec.NodeX509IssuerSerial) is None: 
    705                 raise XMLSecDocError("Error adding %s node" % \ 
    706                                      xmlsec.NodeX509IssuerSerial) 
    707  
    708  
    709         # Create signature context 
    710         self.__xmlsecDSigCtx() 
    711  
    712          
    713         # Load private key 
    714         self.__dSigCtxt.signKey = xmlsec.cryptoAppKeyLoad( 
    715                                                     self.__signingKeyFilePath, 
    716                                                     xmlsec.KeyDataFormatPem, 
    717                                                     signingKeyPwd, 
    718                                                     None,  
    719                                                     None) 
    720         if self.__dSigCtxt.signKey is None: 
    721             raise XMLSecDocError(\ 
    722                 "Error loading private pem key from \"%s\"" % \ 
    723                 self.__signingKeyFilePath) 
    724  
    725  
    726         # Load certificate and add to the key 
    727         if xmlsec.cryptoAppKeyCertLoad(self.__dSigCtxt.signKey, 
    728                                        self.__certFilePathList[0], 
    729                                        xmlsec.KeyDataFormatPem) < 0: 
    730             raise XMLSecDocError("Error loading pem certificate \"%s\"" % \ 
    731                                   self.__certFilePathList[0]) 
    732  
    733  
    734         # Set key name to the file name 
    735         if self.__dSigCtxt.signKey.setName(self.__signingKeyFilePath) < 0: 
    736             raise XMLSecDocError(\ 
    737                 "Error setting key name for key from \"%s\"" % \ 
    738                   self.__signingKeyFilePath) 
    739  
    740  
    741         # Sign the template 
    742         if self.__dSigCtxt.sign(sigNode) < 0: 
    743             raise XMLSecDocError("Signature failed") 
    744  
    745              
    746         # Return as required 
    747         if rtnAsString: 
    748             return self.asString() 
    749          
    750  
    751     #_________________________________________________________________________ 
    752     def isValidSig(self, 
    753                    xmlTxt=None, 
    754                    filePath=None, 
    755                    certFilePathList=None): 
    756  
    757         """ 
    758         Verify XML signature in file.  Returns True if valid otherwise 
    759         False. 
    760  
    761         xmlTxt:                 string buffer containing the text from the XML 
    762                                 file to be checked.  If omitted, the 
    763                                 filePath argument is used instead. 
    764  
    765         filePath:               file path to XML file to be checked.  This 
    766                                 argument is used if no xmlTxt was provided. 
    767                                 If filePath itself is omitted the file set 
    768                                 by self.__filePath is read instead. 
    769  
    770         certFilePathList:       Certificate used to sign the document. 
    771                                 """ 
    772  
    773         if certFilePathList is not None: 
    774             self.__setCertFilePathList(certFilePathList) 
    775  
    776          
    777         # Check Certificate files for read access 
    778         if not self.__certFilePathList:                 
    779             raise XMLSecDocError("No certificate files set for check") 
    780              
    781  
    782         # Create and initialize keys manager 
    783         self.__xmlsecKeysMngr() 
    784  
    785         if xmlsec.cryptoAppDefaultKeysMngrInit(self.__keysMngr) < 0: 
    786             raise XMLSecDocError("Failed to initialize keys manager.") 
    787  
    788          
    789         # Load certificate(s) list should contain certificate used to sign the 
    790         # document 
    791         for certFilePath in self.__certFilePathList: 
    792             if self.__keysMngr.certLoad(certFilePath, 
    793                                         xmlsec.KeyDataFormatPem, 
    794                                         xmlsec.KeyDataTypeTrusted) < 0: 
    795                 raise XMLSecDocError(\ 
    796                     "Error loading signing certificate \"%s\"" % certFilePath) 
    797  
    798  
    799         # If 'xmlTxt' was input, update libxml2 doc instance with it's content 
    800         if xmlTxt is not None:  
    801             self.__libxml2ParseDoc(xmlTxt) 
    802              
    803         elif filePath: 
    804             # Likewise, if a new file was set 
    805             self.__setFilePath(filePath)                 
    806             self.__libxml2ParseFile() 
    807          
    808         # libxml2Doc should now be instantiated - from xmlTxt, an input file 
    809         # or previous call to parse or read document 
    810         if not self.__libxml2Doc: 
    811             raise XMLSecDocError("document is invalid") 
    812  
    813         
    814         # Find start node 
    815         dSigNode = xmlsec.findNode(self.__libxml2Doc.getRootElement(), 
    816                                    xmlsec.NodeSignature, xmlsec.DSigNs) 
    817         if dSigNode is None: 
    818             raise XMLSecDocError(\ 
    819                 "Start node not found in \"%s\"" % self.__filePath) 
    820  
    821   
    822         # Create signature context 
    823         self.__xmlsecDSigCtx(self.__keysMngr) 
    824  
    825  
    826         # Verify signature 
    827         if self.__dSigCtxt.verify(dSigNode) < 0: 
    828             raise XMLSecDocError("Error verifying signature.") 
    829  
    830  
    831         # Return True if signature is OK, False otherwise 
    832         return self.__dSigCtxt.status == xmlsec.DSigStatusSucceeded 
    833  
    834  
    835     #_________________________________________________________________________ 
    836     def getKeyInfoData(self): 
    837         """Return tags associated with KeyInfo tag of digital signature as a 
    838         dictionary 
    839  
    840         Call after isValidSig() or read()""" 
    841  
    842         keyInfo = {} 
    843  
    844          
    845         # Find start node 
    846         dSigNode = xmlsec.findNode(self.__libxml2Doc.getRootElement(), 
    847                                    xmlsec.NodeSignature,  
    848                                    xmlsec.DSigNs) 
    849         if dSigNode is None: 
    850             raise XMLSecDocError(\ 
    851                 "Start node not found in \"%s\"" % self.__filePath) 
    852          
    853              
    854         keyInfoNode = xmlsec.findNode(dSigNode, 
    855                                       xmlsec.NodeKeyInfo, 
    856                                       xmlsec.DSigNs) 
    857         if keyInfoNode is None: 
    858             raise XMLSecDocError("KeyInfo node not found in \"%s\"" % \ 
    859                                  self.__filePath) 
    860  
    861              
    862         keyNameNode = xmlsec.findNode(keyInfoNode, 
    863                                       xmlsec.NodeKeyName, 
    864                                       xmlsec.DSigNs) 
    865         if keyNameNode is not None: 
    866             keyInfo[keyNameNode.name] = keyNameNode.content 
    867  
    868              
    869         x509DataNode = xmlsec.findNode(keyInfoNode, 
    870                                        xmlsec.NodeX509Data, 
    871                                        xmlsec.DSigNs) 
    872         if x509DataNode is None: 
    873             # Return the keyInfo found up to this point 
    874             return keyInfo 
    875  
    876         keyInfo[x509DataNode.name] = {} 
    877  
    878          
    879         x509CertificateNode = xmlsec.findNode(x509DataNode, 
    880                                               xmlsec.NodeX509Certificate, 
    881                                               xmlsec.DSigNs) 
    882         if x509CertificateNode is not None: 
    883             keyInfo[x509DataNode.name][x509CertificateNode.name] = \ 
    884                                                 x509CertificateNode.content 
    885  
    886  
    887         x509SubjectNameNode = xmlsec.findNode(x509DataNode, 
    888                                               xmlsec.NodeX509SubjectName, 
    889                                               xmlsec.DSigNs) 
    890         if x509SubjectNameNode is not None: 
    891             keyInfo[x509DataNode.name][x509SubjectNameNode.name] = \ 
    892                                                 x509SubjectNameNode.content 
    893  
    894  
    895         x509IssuerSerialNode = xmlsec.findNode(x509DataNode, 
    896                                                xmlsec.NodeX509IssuerSerial, 
    897                                                xmlsec.DSigNs) 
    898         if x509IssuerSerialNode is None: 
    899             # Return the keyInfo found up to this point 
    900             return keyInfo 
    901  
    902  
    903         keyInfo[x509DataNode.name][x509IssuerSerialNode.name] = {} 
    904          
    905         x509IssuerNameNode = xmlsec.findNode(x509IssuerSerialNode, 
    906                                              xmlsec.NodeX509IssuerName, 
    907                                              xmlsec.DSigNs) 
    908         if x509IssuerNameNode is not None:             
    909             keyInfo[x509DataNode.name][x509IssuerSerialNode.name]\ 
    910                     [x509IssuerNameNode.name] = x509IssuerNameNode.content 
    911  
    912  
    913         x509SerialNumberNode = xmlsec.findNode(x509IssuerSerialNode, 
    914                                                xmlsec.NodeX509SerialNumber, 
    915                                                xmlsec.DSigNs) 
    916         if x509SerialNumberNode is not None:             
    917             keyInfo[x509DataNode.name][x509IssuerSerialNode.name]\ 
    918                     [x509SerialNumberNode.name] = x509SerialNumberNode.content 
    919  
    920  
    921         return keyInfo 
    922      
    923  
    924     #_________________________________________________________________________ 
    925     def encrypt(self, 
    926                 xmlTxt=None,  
    927                 filePath=None,  
    928                 encrCertFilePath=None, 
    929                 inclX509SubjName=True, 
    930                 inclX509IssSerial=True, 
    931                 rtnAsString=False): 
    932         """Encrypt a document using recipient's public key 
    933  
    934         Encrypts xml file using a dynamically created template, a session  
    935         triple DES key and an RSA key from keys manager. 
    936          
    937         xmlTxt:                 string buffer containing the text from the XML 
    938                                 file to be encrypted.  If omitted, the 
    939                                 filePath argument is used instead. 
    940  
    941         filePath:               file path to XML file to be encrypted.  This 
    942                                 argument is used if no xmlTxt was provided. 
    943                                 If filePath itself is omitted the file set 
    944                                 by self.__filePath is read instead. 
    945                                  
    946         encrCertFilePath:     file path to RSA public key file used to 
    947                                 encrypt the document. 
    948                                  
    949         inclX509SubjName:       include subject name of signing X.509  
    950                                 certificate. 
    951         inclX509IssSerial:      include issuer name and serial number in 
    952                                 signature     
    953          
    954         rtnAsString:            This method returns None by default.  Set to  
    955                                 True to override and return the encrypted 
    956                                 result instead as a string.""" 
    957          
    958         if encrCertFilePath: 
    959             self.__setEncrCertFilePath(encrCertFilePath) 
    960              
    961              
    962         # Create file based Keys manager to load the public key used to  
    963         self.__xmlsecKeysMngr() 
    964  
    965  
    966         if xmlsec.cryptoAppDefaultKeysMngrInit(self.__keysMngr) < 0: 
    967             raise XMLSecDocError("Error initializing keys manager.") 
    968  
    969  
    970         # Load public RSA key 
    971         # 
    972         # Nb. 7 value corresponds to XMLSec "xmlSecKeyDataFormatCertPem" -  
    973         # there isn't a variable set up for it in pyXMLSec 
    974         encrKey = xmlsec.cryptoAppKeyLoad(self.__encrCertFilePath,  
    975                                           7, 
    976                                           None,  
    977                                           None,  
    978                                           None); 
    979         if encrKey is None: 
    980             raise XMLSecDocError(\ 
    981                 "Error loading RSA public key from file \"%s\"" % \ 
    982                 self.__encrCertFilePath) 
    983  
    984  
    985         # Set key name to the file name, this is just an example! 
    986         if encrKey.setName(self.__encrCertFilePath) < 0: 
    987             raise XMLSecDocError(\ 
    988                 "Error setting key name for RSA public key from \"%s\"" % \ 
    989                 self.__encrCertFilePath) 
    990  
    991  
    992         # Add key to keys manager, from now on keys manager is responsible 
    993         # for destroying key 
    994         if xmlsec.cryptoAppDefaultKeysMngrAdoptKey(self.__keysMngr,  
    995                                                    encrKey) < 0: 
    996             raise XMLSecDocError(\ 
    997                 "Error adding RSA public key from \"%s\" to keys manager" % \ 
    998                 self.__encrCertFilePath) 
    999  
    1000     
    1001         # If 'xmlTxt' was input update libxml2 doc instance with it's content 
    1002         if xmlTxt:  
    1003             self.__libxml2ParseDoc(xmlTxt) 
    1004         else: 
    1005             # Update file path if set - otherwise, existing setting   
    1006             # self.__filePath will be used. 
    1007             if filePath: 
    1008                 self.__setFilePath(filePath) 
    1009                  
    1010                 # Read XML document from file 
    1011                 self.__libxml2ParseFile() 
    1012  
    1013      
    1014         # Create encryption template to encrypt XML file and replace  
    1015         # its content with encryption result 
    1016         encrNode = xmlsec.TmplEncData(self.__libxml2Doc,  
    1017                                       xmlsec.transformDes3CbcId(), 
    1018                                       None,  
    1019                                       xmlsec.TypeEncElement,  
    1020                                       None,  
    1021                                       None) 
    1022         if encrNode is None: 
    1023             raise XMLSecDocError("Error creating encryption template") 
    1024  
    1025      
    1026         # Put encrypted data in the <enc:CipherValue/> node 
    1027         if encrNode.ensureCipherValue() is None: 
    1028             raise XMLSecDocError("Error adding CipherValue node") 
    1029   
    1030      
    1031         # add <dsig:KeyInfo/> 
    1032         keyInfoNode = encrNode.ensureKeyInfo(None) 
    1033         if keyInfoNode is None: 
    1034             XMLSecDocError("Error adding key info node") 
    1035  
    1036      
    1037         # Add <enc:EncryptedKey/> to store the encrypted session key 
    1038         encrKeyNode = keyInfoNode.addEncryptedKey(xmlsec.transformRsaOaepId(),  
    1039                                                   None,  
    1040                                                   None,  
    1041                                                   None) 
    1042         if encrKeyNode is None: 
    1043             XMLSecDocError("Error adding encryption key info node") 
    1044  
    1045      
    1046         # Put encrypted key in the <enc:CipherValue/> node 
    1047         if encrKeyNode.ensureCipherValue() is None: 
    1048             XMLSecDocError("Error adding CipherValue node") 
    1049  
    1050      
    1051         keyInfoNode2 = encrKeyNode.ensureKeyInfo(None) 
    1052         if keyInfoNode2 is None: 
    1053             XMLSecDocError("Error adding public key <KeyInfo>") 
    1054             
    1055          
    1056         # Add info about public key in <KeyInfo> <X509Data> if any of X.509 
    1057         # flags are set 
    1058         if inclX509SubjName or inclX509IssSerial: 
    1059              
    1060             keyInfoNode2 = encrKeyNode.ensureKeyInfo(None) 
    1061             if keyInfoNode2 is None: 
    1062                 XMLSecDocError("Error adding public key <KeyInfo>") 
    1063                 cleanup(self.__libxml2Doc, encrNode) 
    1064          
    1065          
    1066             x509DataNode = keyInfoNode2.addX509Data() 
    1067             if x509DataNode is None: 
    1068                 raise XMLSecDocError("Error adding <X509Data> node") 
    1069      
    1070      
    1071             # Individual X509Data components 
    1072             if inclX509SubjName: 
    1073                 if xmlsec.addChild(x509DataNode, 
    1074                                    xmlsec.NodeX509SubjectName) is None: 
    1075                     raise XMLSecDocError("Error adding <%s> node" % \ 
    1076                                          xmlsec.NodeX509SubjectName) 
    1077          
    1078             if inclX509IssSerial: 
    1079                 if xmlsec.addChild(x509DataNode, 
    1080                                    xmlsec.NodeX509IssuerSerial) is None: 
    1081                     raise XMLSecDocError("Error adding <%s> node" % \ 
    1082                                          xmlsec.NodeX509IssuerSerial) 
    1083      
    1084              
    1085         # Create encryption context 
    1086         self.__xmlsecEncCtx(self.__keysMngr) 
    1087  
    1088      
    1089         # Generate a Triple DES key 
    1090         self.__encCtxt.encKey = xmlsec.keyGenerate(xmlsec.keyDataDesId(),  
    1091                                                    192, 
    1092                                                    xmlsec.KeyDataTypeSession) 
    1093         if self.__encCtxt.encKey is None: 
    1094             raise XMLSecDocError("Error generating session DES key") 
    1095      
    1096      
    1097         # Encrypt the data 
    1098         if self.__encCtxt.xmlEncrypt(encrNode,  
    1099                                      self.__libxml2Doc.getRootElement()) < 0: 
    1100             raise XMLSecDocError("Encryption failed") 
    1101      
    1102  
    1103         # Success 
    1104         if rtnAsString: 
    1105             return self.asString() 
    1106   
    1107   
    1108     #_________________________________________________________________________ 
    1109     def decrypt(self,  
    1110                 xmlTxt=None,  
    1111                 filePath=None,  
    1112                 encrPriKeyFilePath=None, 
    1113                 encrPriKeyPwd=None, 
    1114                 rtnAsString=False): 
    1115         """Decrypt a document using a private key of public/private key pair 
    1116          
    1117         xmlTxt:                 string buffer containing the text from the XML 
    1118                                 file to be decrypted.  If omitted, the 
    1119                                 filePath argument is used instead. 
    1120  
    1121         filePath:               file path to XML file to be decrypted.  This 
    1122                                 argument is used if no xmlTxt was provided. 
    1123                                 If filePath itself is omitted the file set 
    1124                                 by self.__filePath is read instead. 
    1125                                  
    1126         encrPriKeyFilePath:     file path to private key file used to decrypt 
    1127  
    1128         encrPriKeyPwd:          password for private key file. 
    1129          
    1130         rtnAsString:            This method returns None by default.  Set to  
    1131                                 True to override and return the decrypted 
    1132                                 result instead as a string.""" 
    1133          
    1134         if encrPriKeyFilePath: 
    1135             self.__setEncrPriKeyFilePath(encrPriKeyFilePath) 
    1136              
    1137              
    1138         # Create Keys manager to hold the private key used to decrypt 
    1139         self.__xmlsecKeysMngr() 
    1140  
    1141         if xmlsec.cryptoAppDefaultKeysMngrInit(self.__keysMngr) < 0: 
    1142             raise XMLSecDocError("Error initializing keys manager.") 
    1143  
    1144          
    1145         encrKey = xmlsec.cryptoAppKeyLoad(self.__encrPriKeyFilePath,  
    1146                                           xmlsec.KeyDataFormatPem,  
    1147                                           encrPriKeyPwd,  
    1148                                           None,  
    1149                                           None) 
    1150         if encrKey is None: 
    1151             raise XMLSecDocError(\ 
    1152                 "Error loading private key from file \"%s\"" % \ 
    1153                 self.__encrPriKeyFilePath) 
    1154   
    1155          
    1156         # Add key to keys manager, from now on keys manager is responsible 
    1157         # for destroying key 
    1158         if xmlsec.cryptoAppDefaultKeysMngrAdoptKey(self.__keysMngr,  
    1159                                                    encrKey) < 0: 
    1160             raise XMLSecDocError(\ 
    1161                 "Error adding private key from \"%s\" to keys manager" % \ 
    1162                 self.__encrPriKeyFilePath) 
    1163   
    1164     
    1165         # If 'xmlTxt' was input update libxml2 doc instance with it's content 
    1166         if xmlTxt:  
    1167             self.__libxml2ParseDoc(xmlTxt) 
    1168         else: 
    1169             # Update file path if set - otherwise, existing setting   
    1170             # self.__filePath will be used. 
    1171             if filePath: 
    1172                 self.__setFilePath(filePath) 
    1173              
    1174             # Read XML document from file 
    1175             self.__libxml2ParseFile() 
    1176                
    1177                 
    1178         # Find start node 
    1179         encrNode = xmlsec.findNode(self.__libxml2Doc.getRootElement(),  
    1180                                    xmlsec.NodeEncryptedData, 
    1181                                    xmlsec.EncNs) 
    1182         if encrNode is None: 
    1183             raise XMLSecDocError("Start node not found") 
    1184          
    1185          
    1186         # Create encryption context 
    1187         self.__xmlsecEncCtx(self.__keysMngr) 
    1188  
    1189      
    1190         # Decrypt the data 
    1191         if self.__encCtxt.decrypt(encrNode) < 0 or \ 
    1192            self.__encCtxt.result is None: 
    1193             raise XMLSecDocError("Decryption failed") 
    1194      
    1195         # Check 
    1196         if not self.__encCtxt.resultReplaced: 
    1197             raise XMLSecDocError("Expecting XML data result") 
    1198      
    1199         # Success 
    1200         if rtnAsString: 
    1201             return self.asString() 
    1202  
    1203  
    1204     #_________________________________________________________________________ 
    1205     def symEncrypt(self,  
    1206                    xmlTxt=None,  
    1207                    filePath=None, 
    1208                    keyBinFilePath=None,  
    1209                    rtnAsString=False): 
    1210         """Encrypt document using symmetric key 
    1211  
    1212         xmlTxt:                 string buffer containing the text from the XML 
    1213                                 file to be encrypted.  If omitted, the 
    1214                                 filePath argument is used instead. 
    1215  
    1216         filePath:               file path to XML file to be encrypted.  This 
    1217                                 argument is used if no xmlTxt was provided. 
    1218                                 If filePath itself is omitted the file set 
    1219                                 by self.__filePath is read instead. 
    1220                                  
    1221         keyBinFilePath:         file path to binary file containing DES key 
    1222                                 used to encrypt.  If none provided,  
    1223                                 dynamically generate one. 
    1224  
    1225         rtnAsString:            This method returns None by default.  Set to  
    1226                                 True to override and return the encrypted 
    1227                                 result instead as a string.""" 
    1228  
    1229     
    1230         # If 'xmlTxt' was input update libxml2 doc instance with it's content 
    1231         if xmlTxt:  
    1232             self.__libxml2ParseDoc(xmlTxt) 
    1233         elif filePath: 
    1234             # Update file path if set - otherwise, existing setting   
    1235             # self.__filePath will be used.             
    1236             self.__setFilePath(filePath) 
    1237              
    1238             # Read XML document from file 
    1239             self.__libxml2ParseFile() 
    1240  
    1241          
    1242         # Create encryption template to encrypt XML file and replace  
    1243         # its content with encryption result 
    1244         encrNode = xmlsec.TmplEncData(self.__libxml2Doc,  
    1245                                       xmlsec.transformDes3CbcId(), 
    1246                                       None,  
    1247                                       xmlsec.TypeEncElement,  
    1248                                       None,  
    1249                                       None) 
    1250         if encrNode is None: 
    1251             raise XMLSecDocError("Error creating encryption template") 
    1252      
    1253         # Put encrypted data in the <enc:CipherValue/> node 
    1254         if encrNode.ensureCipherValue() is None: 
    1255             raise XMLSecDocError("Error adding CipherValue node") 
    1256      
    1257         # add <dsig:KeyInfo/> 
    1258         keyInfoNode = encrNode.ensureKeyInfo(None) 
    1259         if keyInfoNode is None: 
    1260             XMLSecDocError("Error adding key info node") 
    1261        
    1262        
    1263         if keyInfoNode.addKeyName() is None: 
    1264             XMLSecDocError("Error adding key name") 
    1265              
    1266              
    1267         # Create encryption context, no keys manager is needed 
    1268         self.__xmlsecEncCtx() 
    1269      
    1270         if keyBinFilePath: 
    1271             # Load DES key from file, assume that there is no password 
    1272             self.__encCtxt.encKey = xmlsec.keyReadBinaryFile(\ 
    1273                                                    xmlsec.keyDataDesId(),  
    1274                                                    keyBinFilePath)                 
    1275         else: 
    1276             # Generate a Triple DES key dynamically 
    1277             self.__encCtxt.encKey = xmlsec.keyGenerate(xmlsec.keyDataDesId(),  
    1278                                                    192, 
    1279                                                    xmlsec.KeyDataTypeSession) 
    1280  
    1281         if self.__encCtxt.encKey is None: 
    1282             raise XMLSecDocError("Error setting DES key") 
    1283      
    1284       
    1285         # Set key name 
    1286         if self.__encCtxt.encKey.setName(os.path.basename(keyBinFilePath))<0: 
    1287             raise XMLSecDocError("Error setting key name") 
    1288  
    1289      
    1290         # Encrypt the data 
    1291         if self.__encCtxt.xmlEncrypt(encrNode,  
    1292                                      self.__libxml2Doc.getRootElement()) < 0: 
    1293             raise XMLSecDocError("Encryption failed") 
    1294      
    1295         # Success 
    1296         if rtnAsString: 
    1297             return self.asString() 
    1298          
    1299          
    1300     #_________________________________________________________________________ 
    1301     def symDecrypt(self, 
    1302                    xmlTxt=None,  
    1303                    filePath=None, 
    1304                    keyBinFilePath=None, 
    1305                    rtnAsString=False):                        
    1306         """Decrypt XML encrypted with a symmetric key 
    1307          
    1308         xmlTxt:                 string buffer containing the text from the XML 
    1309                                 file to be checked.  If omitted, the 
    1310                                 filePath argument is used instead. 
    1311  
    1312         filePath:               file path to XML file to be checked.  This 
    1313                                 argument is used if no xmlTxt was provided. 
    1314                                 If filePath itself is omitted the file set 
    1315                                 by self.__filePath is read instead. 
    1316                                  
    1317         keyBinFilePath:         file path to binary file containing DES key 
    1318                                 used to decrypt 
    1319  
    1320         rtnAsString:            This method returns None by default.  Set to  
    1321                                 True to override and return the decrypted 
    1322                                 result instead as a string.""" 
    1323                                  
    1324         # Load key into keys manager 
    1325         self.__xmlsecKeysMngr() 
    1326  
    1327         if xmlsec.cryptoAppDefaultKeysMngrInit(self.__keysMngr) < 0: 
    1328             raise XMLSecDocError("Error initializing keys manager.") 
    1329          
    1330         # Load DES key 
    1331         encrKey = xmlsec.keyReadBinaryFile(xmlsec.keyDataDesId(),  
    1332                                            keyBinFilePath) 
    1333         if encrKey is None: 
    1334             raise XMLSecDocError(\ 
    1335                 "Error loading DES key from binary file \"%s\"" % \ 
    1336                 keyBinFilePath) 
    1337  
    1338         # Add key to keys manager, from now on keys manager is responsible 
    1339         # for destroying key 
    1340         if xmlsec.cryptoAppDefaultKeysMngrAdoptKey(self.__keysMngr,  
    1341                                                    encrKey) < 0: 
    1342             raise XMLSecDocError(\ 
    1343                 "Error adding DES key from \"%s\" to keys manager" % \ 
    1344                 keyBinFilePath) 
    1345  
    1346      
    1347         # If 'xmlTxt' was input update libxml2 doc instance with it's content 
    1348         if xmlTxt:  
    1349             self.__libxml2ParseDoc(xmlTxt) 
    1350         else: 
    1351             # Update file path if set - otherwise, existing setting   
    1352             # self.__filePath will be used. 
    1353             if filePath: 
    1354                 self.__setFilePath(filePath) 
    1355              
    1356             # Read XML document from file 
    1357             self.__libxml2ParseFile() 
    1358                
    1359                 
    1360         # Find start node 
    1361         encrNode = xmlsec.findNode(self.__libxml2Doc.getRootElement(),  
    1362                                    xmlsec.NodeEncryptedData, 
    1363                                    xmlsec.EncNs) 
    1364         if encrNode is None: 
    1365             raise XMLSecDocError("Start node not found in \"%s\"" % \ 
    1366                                                             self.__filePath) 
    1367                 
    1368         # Create encryption context 
    1369         self.__xmlsecEncCtx(self.__keysMngr) 
    1370  
    1371      
    1372         # Decrypt the data 
    1373         if self.__encCtxt.decrypt(encrNode) < 0 or \ 
    1374            self.__encCtxt.result is None: 
    1375             raise XMLSecDocError("Decryption failed") 
    1376      
    1377         # Check 
    1378         if not self.__encCtxt.resultReplaced: 
    1379             raise XMLSecDocError("Expecting XML data result") 
    1380      
    1381         # Success 
    1382         if rtnAsString: 
    1383             return self.asString() 
    1384  
    1385  
    1386     def generateSymKey(self, keyLength=192, outFilePath=None): 
    1387         """Generate a symmetric key for encrypting a document 
    1388          
    1389         keyLength:    length of key in characters - must 192 or greater 
    1390         outFilePath:  if a file path is provided, write the key to this file 
    1391         """ 
    1392          
    1393         if keyLength < 192: 
    1394             keyLength = 192 
    1395              
    1396         try: 
    1397             key = base64.urlsafe_b64encode(os.urandom(keyLength))[0:192] 
    1398         except Exception, e: 
    1399             raise XMLSecDocError("Error creating symmetric key") 
    1400          
    1401         if outFilePath: 
    1402             try: 
    1403                 open(outFilePath, "w").write(key) 
    1404                  
    1405             except IOError, e: 
    1406                 raise XMLSecDocError(\ 
    1407                     "Error writing key to file \"%s\": %s" % \ 
    1408                                      (e.filename, e.strerror)) 
    1409             except Exception, e: 
    1410                 raise XMLSecDocError("Error writing key to file \"%s\"" %\ 
    1411                                      outFilePath) 
    1412                                   
    1413         return key 
    1414  
    1415 ############################################################################## 
    1416 class XMLSecDoc(object): 
    1417     """Implements XML Signature and XML Encryption for a Document.""" 
    1418  
    1419     def __init__(self, 
    1420                  filePath=None, 
    1421                  signingKeyFilePath=None, 
    1422                  encrCertFilePath=None, 
    1423                  encrPriKeyFilePath=None, 
    1424                  certFilePathList=None): 
     78                 encrPriKeyFilePath=None): 
    142579 
    142680        """Initialisation - 
     
    142983        @param signingKeyFilePath:  file path for private key used in  
    143084        signature 
     85        @param certFilePathList:    list of certificates used in verification  
     86        of a signed document 
     87        @param encrCertFilePath:    file path for X.509 cert used to encrypt 
     88        the document 
    143189        @param encrPriKeyFilePath:  file path for private key used to decrypt 
    1432         previously encrypted document 
    1433         @param certFilePathList:    list of certificates used in verification  
    1434         of a signed document""" 
     90        previously encrypted document""" 
    143591 
    143692        self.__filePath = None 
     
    1467123        """String representation of doc - only applies if doc had been read 
    1468124        or parsed""" 
    1469  
     125        self.toString() 
     126         
    1470127 
    1471128    def __getFilePath(self): 
     
    1511168 
    1512169    #_________________________________________________________________________ 
    1513     def __setCertdocNodeList(self, filePath): 
     170    def __setCertFilePathList(self, filePath): 
    1514171        """File path for certificate used to sign document /  
    1515172        list of certificates used to check the signature of a document""" 
     
    1547204    # Publish attribute as write only 
    1548205    signingKeyFilePath = property(fset=__setSigningKeyFilePath, 
    1549                 doc="file path for certificate private key used to sign doc") 
     206                          doc="path for private key file used to sign doc") 
     207 
     208 
     209    #_________________________________________________________________________ 
     210    def __setSigningKeyPwd(self, pwd): 
     211        """Set password to read private key from file""" 
     212         
     213        if pwd is not None and not isinstance(pwd, basestring):             
     214            raise XMLSecDocError, \ 
     215            "Private key password must be set to None or to a valid string" 
     216         
     217        self.__signingKeyPwd = pwd 
     218 
     219    # Publish attribute as write only 
     220    signingKeyPwd = property(fset=__setSigningKeyPwd, 
     221                doc="Password protecting private key file used to sign doc") 
    1550222 
    1551223 
     
    1582254 
    1583255    #_________________________________________________________________________ 
    1584     def asString(self, filePath=None, stripXMLhdr=False): 
    1585         """Return certificate file content as a string""" 
    1586          
    1587         # Check libxml2.xmlDoc object has been instantiated - if not call 
    1588         # read method 
    1589         if self.__libxml2Doc is None: 
    1590             if filePath is None: 
    1591                 raise XMLSecDocError, \ 
    1592                     "A file must be parsed first for asString()" 
    1593                      
    1594             self.read(filePath) 
    1595  
    1596         try: 
    1597             # Make a buffer 
    1598             f = StringIO() 
    1599             buf = libxml2.createOutputBuffer(f, 'UTF-8') 
    1600  
    1601             # Write to buffer 
    1602             self.__libxml2Doc.saveFormatFileTo(buf, 'UTF-8', 0) 
    1603  
    1604  
    1605             # Return string content 
    1606             if stripXMLhdr: 
    1607                 return re.sub("<\?xml.*>\s", "", f.getvalue()) 
    1608             else: 
    1609                 return f.getvalue() 
    1610  
    1611         except Exception, e: 
    1612             raise XMLSecDocError("Error outputting document as a string:" % \ 
    1613                                  e) 
     256    def toString(self, inclXMLhdr=True): 
     257        """Return certificate file content as a string 
     258         
     259        @param inclXMLhdr: boolean - set to true to include XML header 
     260        @return content of document as a string or None if the document has 
     261        not been parsed.""" 
     262 
     263        if not self.__docNode: 
     264            return None 
     265         
     266        if inclXMLhdr: 
     267            return '<?xml version="1.0" encoding="utf-8"?>\n' + \ 
     268                    Canonicalize(self.__docNode) 
     269        else: 
     270            return Canonicalize(self.__docNode) 
    1614271 
    1615272 
     
    1620277        self.__docNode = Reader().fromString(xmlTxt) 
    1621278 
     279 
    1622280    #_________________________________________________________________________ 
    1623281    def read(self, stream=None): 
    1624  
    1625282        """Read XML into a libxml2 document to allow signature validation""" 
    1626283        if stream is None: 
    1627284            stream = open(self.__filePath) 
    1628285                 
    1629         self.__docNode = Reader.fromStream(stream) 
     286        self.__docNode = Reader().fromStream(stream) 
    1630287 
    1631288 
     
    1633290    def write(self): 
    1634291        """Write XML document""" 
    1635  
    1636  
    1637     #_________________________________________________________________________ 
    1638     def createXML(self): 
    1639         """VIRTUAL method - derived class should implement - 
    1640         Create text for output and return as a string""" 
    1641          
    1642         """A new user to Credentials Repository""" 
    1643         raise NotImplementedError, \ 
    1644                                 self.createXML.__doc__.replace('\n       ','') 
     292        open(self.__filePath, 'w').write(self.toString()) 
    1645293 
    1646294 
     
    1648296    def sign(self, 
    1649297             xmlTxt=None, 
    1650              signingKeyFilePath=None, 
    1651              signingKeyPwd=None, 
    1652              certFilePathList=None, 
    1653298             inclX509Cert=True, 
    1654              inclX509SubjName=True, 
    1655              inclX509IssSerial=True, 
    1656              rtnAsString=False, 
    1657299             **c14nKw): 
    1658300        """Sign XML document using an X.509 certificate private key 
    1659301 
    1660         xmlTxt:                 string buffer containing xml to be signed. If 
     302        @param xmlTxt:          string buffer containing xml to be signed. If 
    1661303                                not provided, calls XMLSecDoc.createXML(). 
    1662304                                This is a virtual method so must be defined 
    1663305                                in a derived class. 
    1664306                             
    1665         signingKeyFilePath:     file path to private key file used to sign 
    1666                                 the document 
    1667  
    1668         signingKeyPwd:          password for signing key file. 
    1669          
    1670         certFilePathList:        include certificate of signer  
    1671         inclX509Cert:            include MIME encoded content of X.509  
    1672                                 certificate that will sign the document 
    1673         inclX509SubjName:        include subject name of signing X.509  
    1674                                 certificate. 
    1675         inclX509IssSerial:        include issuer name and serial inumber in 
    1676                                 signature 
    1677                                      
    1678         rtnAsString:            This method returns None by default.  Set to  
    1679                                 True to override and return the signed 
    1680                                 result instead as a string.""" 
    1681  
    1682         # Create string buffer from virtual function if not passed 
    1683         # as input argument - derived class must implement  
     307        @param inclX509Cert:    include MIME encoded content of X.509 
     308                                certificate.  This can be used by the  
     309                                recipient of the XML in order to verify the 
     310                                message""" 
     311 
    1684312        if xmlTxt: 
    1685313            self.parse(xmlTxt) 
    1686314 
    1687315        if self.__docNode is None: 
    1688             XMLSecDocError, "XML to be signed has not been read in or parsed." 
    1689                 
    1690         # Set private key file 
    1691         if signingKeyFilePath is not None: 
    1692             self.__setSigningKeyFilePath(signingKeyFilePath)             
    1693  
    1694  
    1695         # Public certificate file  
    1696         if certFilePathList is not None: 
    1697             self.__setCertFilePathList(certFilePathList) 
    1698  
    1699         self.__docNode.setNamespaceAttribute('ds', DSIG.BASE) 
    1700         self.__docNode.setNamespaceAttribute('ec', DSIG.C14N_EXCL) 
    1701  
    1702          
    1703         # Signature 
    1704         signatureElem = self.__docNode.createAppendElement(DSIG.BASE,  
    1705                                                            'Signature') 
    1706         signatureElem.setNamespaceAttribute('ds', DSIG.BASE) 
    1707          
    1708         # Signature - Signed Info 
    1709         signedInfoElem = signatureElem.createAppendElement(DSIG.BASE,  
    1710                                                            'SignedInfo') 
    1711          
    1712         # Signed Info - Canonicalization method 
    1713         signedInfoC14nKw = {} 
    1714         signedInfoC14nKw['unsuppressedPrefixes'] = ['ds'] 
    1715         c14nMethodElem = signedInfoElem.createAppendElement(DSIG.BASE, 
    1716                                                     'CanonicalizationMethod') 
    1717         c14nMethodElem.node.setAttribute('Algorithm', DSIG.C14N_EXCL) 
    1718         c14nInclNamespacesElem = c14nMethodElem.createAppendElement(\ 
    1719                                                     DSIG.C14N_EXCL, 
    1720                                                     'InclusiveNamespaces') 
    1721         c14nInclNamespacesElem.node.setAttribute('PrefixList',  
    1722             ' '.join(signedInfoC14nKw['unsuppressedPrefixes'])) 
    1723          
    1724         # Signed Info - Signature method 
    1725         sigMethodElem = signedInfoElem.createAppendElement(DSIG.BASE, 
    1726                                                     'SignatureMethod') 
    1727         sigMethodElem.node.setAttribute('Algorithm', DSIG.SIG_RSA_SHA1) 
    1728          
    1729         # Signature - Signature value 
    1730         signatureValueElem = signatureElem.createAppendElement(DSIG.BASE,  
    1731                                                              'SignatureValue') 
    1732          
    1733         # Key Info 
    1734         KeyInfoElem = signatureElem.createAppendElement(DSIG.BASE, 'KeyInfo') 
    1735  
     316            raise XMLSecDocError, \ 
     317                            "XML to be signed has not been read in or parsed." 
     318 
     319        childNode = self.__docNode.childNodes[1] 
     320        childNode.setAttributeNS(XMLNS.BASE, 'xmlns:%s' % 'ds', DSIG.BASE) 
     321        childNode.setAttributeNS(XMLNS.BASE, 'xmlns:%s'%'ec', DSIG.C14N_EXCL) 
     322         
    1736323        # Serialize and re-parse prior to reference generation - calculating 
    1737324        # canonicalization based on soapWriter.dom.node seems to give an 
    1738325        # error: the order of wsu:Id attribute is not correct 
    1739         docNode = Reader().fromString(str(soapWriter)) 
     326        #docNode = Reader().fromString(str(soapWriter)) 
    1740327         
    1741328        # Namespaces for XPath searches 
    1742329        processorNss = \ 
    1743330        { 
    1744             'ds':     DSIG.BASE,  
     331            'ds':    DSIG.BASE, 
     332            'ec':    DSIG.C14N_EXCL 
    1745333        } 
    1746334        ctxt = Context(self.__docNode, processorNss=processorNss) 
     
    1753341         
    1754342        # Canonicalize reference 
    1755         c14nRef = Canonicalize(idNode, **c14nKw) 
     343        refC14n = Canonicalize(childNode, **c14nKw) 
    1756344         
    1757345        # Calculate digest for reference and base 64 encode 
    1758346        # 
    1759347        # Nb. encodestring adds a trailing newline char 
    1760         digestValue = base64.encodestring(sha(c14nRef).digest()).strip() 
     348        refDigestValue = base64.encodestring(sha(refC14n).digest()).strip() 
     349 
     350 
     351        # Add Signature elements 
     352        signatureNode = self.__docNode.createElementNS(DSIG.BASE, 
     353                                                       'ds:Signature') 
     354        childNode.appendChild(signatureNode) 
     355 
     356         
     357        # Signature - Signed Info 
     358        signedInfoNode = self.__docNode.createElementNS(DSIG.BASE,  
     359                                                        'ds:SignedInfo') 
     360        signatureNode.appendChild(signedInfoNode) 
     361         
     362        # Signed Info - Canonicalization method 
     363        signedInfoC14nKw = {} 
     364        signedInfoC14nKw['unsuppressedPrefixes'] = ['ds'] 
     365         
     366        c14nMethodNode = self.__docNode.createElementNS(DSIG.BASE, 
     367                                                'ds:CanonicalizationMethod')         
     368        c14nMethodNode.setAttribute('Algorithm', DSIG.C14N_EXCL) 
     369        signedInfoNode.appendChild(c14nMethodNode) 
     370 
     371        c14nInclNamespacesNode = self.__docNode.createElementNS(\ 
     372                                                     DSIG.C14N_EXCL, 
     373                                                     'ec:InclusiveNamespaces')        
     374        c14nInclNamespacesNode.setAttribute('PrefixList',  
     375                        ' '.join(signedInfoC14nKw['unsuppressedPrefixes']))         
     376        c14nMethodNode.appendChild(c14nInclNamespacesNode) 
     377         
     378         
     379        # Signed Info - Signature method 
     380        sigMethodNode = self.__docNode.createElementNS(DSIG.BASE, 
     381                                                       'ds:SignatureMethod') 
     382        sigMethodNode.setAttribute('Algorithm', DSIG.SIG_RSA_SHA1) 
     383        signedInfoNode.appendChild(sigMethodNode) 
     384         
     385        # Signature - Signature value 
     386        signatureValueNode = self.__docNode.createElementNS(DSIG.BASE,  
     387                                                        'ds:SignatureValue') 
     388        signatureNode.appendChild(signatureValueNode) 
     389         
     390         
     391        # Key Info 
     392        keyInfoNode = self.__docNode.createElementNS(DSIG.BASE, 'ds:KeyInfo') 
     393        signatureNode.appendChild(keyInfoNode) 
    1761394 
    1762395 
    1763396        # Add a new reference element to SignedInfo 
    1764         refElem = signedInfoElem.createAppendElement(DSIG.BASE, 'Reference') 
    1765          
    1766         # Use ds:Transforms or wsse:TransformationParameters? 
    1767         transformsElem = refElem.createAppendElement(DSIG.BASE,  
    1768                                                     'Transforms') 
    1769         transformElem = transformsElem.createAppendElement(DSIG.BASE,  
    1770                                                            'Transform') 
    1771         transformElem.node.setAttribute('Algorithm', DSIG.C14N_EXCL) 
    1772  
    1773         inclNamespacesElem = transformElem.createAppendElement(\ 
    1774                                                    DSIG.C14N_EXCL, 
    1775                                                    'InclusiveNamespaces') 
    1776         inclNamespacesElem.node.setAttribute('PrefixList', 
     397        refNode = self.__docNode.createElementNS(DSIG.BASE, 'ds:Reference') 
     398        signedInfoNode.appendChild(refNode) 
     399         
     400         
     401        # Add Transforms  
     402        transformsNode = self.__docNode.createElementNS(DSIG.BASE,  
     403                                                        'ds:Transforms') 
     404        refNode.appendChild(transformsNode) 
     405 
     406        # Individual transforms - enveloped digital signature 
     407        transformNode = self.__docNode.createElementNS(DSIG.BASE,  
     408                                                       'ds:Transform') 
     409        transformNode.setAttribute('Algorithm', DSIG.ENVELOPED) 
     410        transformsNode.appendChild(transformNode) 
     411         
     412        # ... - exclusive canonicalization 
     413        transformNode = self.__docNode.createElementNS(DSIG.BASE,  
     414                                                       'ds:Transform') 
     415        transformNode.setAttribute('Algorithm', DSIG.C14N_EXCL) 
     416        transformsNode.appendChild(transformNode) 
     417         
     418        inclNamespacesNode = self.__docNode.createElementNS(\ 
     419                                                       DSIG.C14N_EXCL, 
     420                                                       'InclusiveNamespaces') 
     421        inclNamespacesNode.setAttribute('PrefixList', 
    1777422                                    ' '.join(c14nKw['unsuppressedPrefixes'])) 
     423        transformNode.appendChild(inclNamespacesNode) 
     424         
    1778425         
    1779426        # Digest Method  
    1780         digestMethodElem = refElem.createAppendElement(DSIG.BASE,  
    1781                                                        'DigestMethod') 
    1782         digestMethodElem.node.setAttribute('Algorithm', DSIG.DIGEST_SHA1) 
     427        digestMethodNode = self.__docNode.createElementNS(DSIG.BASE,  
     428                                                          'ds:DigestMethod') 
     429        digestMethodNode.setAttribute('Algorithm', DSIG.DIGEST_SHA1) 
     430        refNode.appendChild(digestMethodNode) 
    1783431         
    1784432        # Digest Value 
    1785         digestValueElem = refElem.createAppendElement(DSIG.BASE,  
    1786                                                       'DigestValue') 
    1787         digestValueElem.createAppendTextNode(digestValue) 
    1788  
    1789     
     433        digestValueNode = self.__docNode.createElementNS(DSIG.BASE,  
     434                                                         'ds:DigestValue') 
     435        refNode.appendChild(digestValueNode) 
     436         
     437        digestValueTxtNode = self.__docNode.createTextNode(refDigestValue) 
     438        digestValueNode.appendChild(digestValueTxtNode) 
     439 
     440 
    1790441        # 2) Signature Generation 
    1791         # 
    1792  
    1793         # Test against signature generated by pyXMLSec version 
    1794         #xmlTxt = open('./wsseSign-xmlsec-res.xml').read() 
    1795         #dom = NonvalidatingReader.parseStream(StringIO(xmlTxt)) 
    1796          
    1797         # Canonicalize the signedInfo node 
    1798         # 
    1799         # Nb. When extracted the code adds the namespace attribute to the 
    1800         # signedInfo!  This has important consequences for validation - 
    1801         # 
    1802         # 1) Do you strip the namespace attribute before taking the digest to  
    1803         # ensure the text is exactly the same as what is displayed in the  
    1804         # message? 
    1805         # 
    1806         # 2) Leave it in and assume the validation algorithm will expect to  
    1807         # add in the namespace attribute?! 
    1808         # 
    1809         # http://www.w3.org/TR/xml-c14n#NoNSPrefixRewriting implies you need  
    1810         # to include namespace declarations for namespaces referenced in a doc 
    1811         # subset - yes to 2) 
    1812         #c14nSignedInfo = signedInfoElem.canonicalize() 
    1813         c14nSignedInfo = Canonicalize(signedInfoElem.node, **signedInfoC14nKw) 
     442        c14nSignedInfo = Canonicalize(signedInfoNode, **signedInfoC14nKw) 
    1814443 
    1815444        # Calculate digest of SignedInfo 
     
    1817446         
    1818447        # Read Private key to sign with     
    1819         priKeyFile = BIO.File(open(self.__priKeyFilePath))                                             
    1820         priKey = RSA.load_key_bio(priKeyFile,  
    1821                                   callback=lambda *ar, **kw: self.__priKeyPwd) 
     448        priKeyFile = BIO.File(open(self.__signingKeyFilePath)) 
     449        priKeyPwdCallback = lambda *ar, **kw: self.__signingKeyPwd 
     450        priKey = RSA.load_key_bio(priKeyFile, callback=priKeyPwdCallback) 
    1822451         
    1823452        # Sign using the private key and base 64 encode the result 
     
    1825454        b64EncSignatureValue = base64.encodestring(signatureValue).strip() 
    1826455 
    1827         # Add to <SignatureValue> 
    1828         signatureValueElem.createAppendTextNode(b64EncSignatureValue) 
    1829          
    1830         # Extract RSA public key from the cert 
    1831         rsaPubKey = x509Cert.get_pubkey().get_rsa() 
    1832          
    1833         # Check the signature  
    1834 #        verify = bool(rsaPubKey.verify(signedInfoDigestValue, signatureValue)) 
    1835 #         
    1836 #        open('soap.xml', 'w').write(str(soapWriter)) 
    1837 #        import pdb;pdb.set_trace()  
    1838         print "Signature Generated" 
    1839         print str(soapWriter) 
     456        # Add to <ds:SignatureValue> 
     457        signatureValueTxtNode = \ 
     458                        self.__docNode.createTextNode(b64EncSignatureValue) 
     459        signatureValueNode.appendChild(signatureValueTxtNode) 
     460         
    1840461         
    1841462        if inclX509Cert: 
    1842             # Add X.509 cert 
    1843             x509Cert = X509.load_cert(self.__certFilePathList[0]) 
     463            if not len(self.__certFilePathList): 
     464                raise XMLSecDocError, \ 
     465                    "No X.509 Certificate set for inclusion in signature" 
     466                     
     467            # Add X.509 cert data 
     468            x509Cert = X509.load_cert(self.__certFilePathList[0])             
     469            x509DataNode = self.__docNode.createElementNS(DSIG.BASE,  
     470                                                          'ds:X509Data') 
     471            keyInfoNode.appendChild(x509DataNode) 
    1844472             
     473         
     474            x509CertNode = self.__docNode.createElementNS(DSIG.BASE,  
     475                                                      'ds:X509Certificate') 
     476            x509DataNode.appendChild(x509CertNode) 
     477 
    1845478            x509CertPat = re.compile(\ 
    1846479            '-----BEGIN CERTIFICATE-----\n?(.*?)\n?-----END CERTIFICATE-----', 
     
    1848481            x509CertStr = x509CertPat.findall(x509Cert.as_pem())[0] 
    1849482                 
    1850             x509CertElem.createAppendTextNode(x509CertStr) 
    1851              
    1852         # Return as required 
    1853         if rtnAsString: 
    1854             return self.asString() 
    1855  
    1856  
    1857          
    1858  
    1859     #_________________________________________________________________________ 
    1860     def verify(self, filePath=None, certFilePathList=None): 
    1861  
    1862         """ 
    1863         Verify XML signature in file.  Returns True if valid otherwise 
     483            x509CertTxtNode = self.__docNode.createTextNode(x509CertStr) 
     484            x509CertNode.appendChild(x509CertTxtNode) 
     485 
     486 
     487    #_________________________________________________________________________ 
     488    def verify(self, xmlTxt=None): 
     489        """Verify XML signature in file.  Returns True if valid otherwise 
    1864490        False. 
    1865491 
     
    1875501        certFilePathList:       Certificate used to sign the document. 
    1876502                                """ 
    1877  
    1878         if certFilePathList is not None: 
    1879             self.__setCertFilePathList(certFilePathList) 
    1880  
    1881          
     503        if self.__docNode is None: 
     504            raise XMLSecDocError, \ 
     505                            "verify signature: no document has been parsed" 
     506 
    1882507        # Check Certificate files for read access 
    1883508        if not self.__certFilePathList:                 
    1884509            raise XMLSecDocError, "No certificate files set for check" 
    1885  
     510         
     511        if xmlTxt: 
     512            self.parse(xmlTxt) 
     513 
     514        import pdb;pdb.set_trace()  
    1886515 
    1887516         
    1888517        processorNss = \ 
    1889518        { 
    1890             'ds':     DSIG.BASE,  
    1891             'wsu':    _WSU.UTILITY,  
    1892             'wsse':   OASIS.WSSE,  
    1893             'soapenv':"http://schemas.xmlsoap.org/soap/envelope/"  
     519            'ds':    DSIG.BASE, 
     520            'ec':    DSIG.C14N_EXCL 
    1894521        } 
    1895         ctxt = Context(parsedSOAP.dom, processorNss=processorNss) 
     522        ctxt = Context(self.__docNode, processorNss=processorNss) 
    1896523         
    1897524 
    1898525        signatureNodes = xpath.Evaluate('//ds:Signature',  
    1899                                         contextNode=parsedSOAP.dom,  
     526                                        contextNode=self.__docNode,  
    1900527                                        context=ctxt) 
    1901528        if len(signatureNodes) > 1: 
     
    1917544        # the transforms elements 
    1918545        c14nMethodNode = xpath.Evaluate('//ds:CanonicalizationMethod',  
    1919                                         contextNode=parsedSOAP.dom,  
     546                                        contextNode=self.__docNode,  
    1920547                                        context=ctxt)[0] 
    1921548         
    1922549        refNodes = xpath.Evaluate('//ds:Reference',  
    1923                                   contextNode=parsedSOAP.dom,  
     550                                  contextNode=self.__docNode,  
    1924551                                  context=ctxt) 
    1925             
    1926         for refNode in refNodes: 
    1927             # Get the URI for the reference 
    1928             refURI = refNode.getAttributeNodeNS(None, 'URI').value 
    1929                              
    1930             try: 
    1931                 transformsNode = getElements(refNode, "Transforms")[0] 
    1932                 transforms = getElements(transformsNode, "Transform") 
    1933      
    1934                 refAlgorithm = transforms[0].getAttributeNodeNS(None,  
    1935                                                          "Algorithm").value 
    1936             except Exception, e: 
    1937                 raise VerifyError, \ 
    1938             'failed to get transform algorithm for <ds:Reference URI="%s">'%\ 
    1939                         (refURI, str(e)) 
    1940                  
    1941             # Add extra keyword for Exclusive canonicalization method 
    1942             c14nKw = {} 
     552        if len(refNodes) > 1: 
     553            raise VerifyError, \ 
     554                "Expecting only one reference element for enveloped signature" 
     555         
     556        refNode = refNodes[0] 
     557         
     558        try: 
     559            transformsNode = getElements(refNode, "Transforms")[0] 
     560            transforms = getElements(transformsNode, "Transform") 
     561 
     562            refAlgorithms = [tfm.getAttributeNodeNS(None, "Algorithm").value \ 
     563                             for tfm in transforms] 
     564        except Exception, e: 
     565            raise VerifyError,'failed to get transform algorithm: %s' % str(e) 
     566             
     567        # Add extra keyword for Exclusive canonicalization method 
     568        refC14nKw = {} 
     569        for transform in transforms: 
     570            refAlgorithm=transform.getAttributeNodeNS(None, "Algorithm").value 
    1943571            if refAlgorithm == DSIG.C14N_EXCL: 
    1944572                try: 
    1945                     inclusiveNS = getElements(transforms[0],  
     573                    inclusiveNS = getElements(transform,  
    1946574                                              "InclusiveNamespaces") 
    1947575                     
     
    1950578                    c14nKw['unsuppressedPrefixes'] = \ 
    1951579                                                pfxListAttNode.value.split() 
    1952                 except: 
     580                    break 
     581                except Exception, e: 
    1953582                    raise VerifyError, \ 
    1954                 'failed to handle transform (%s) in <ds:Reference URI="%s">'%\ 
    1955                         (transforms[0], refURI) 
    1956          
    1957             # Canonicalize the reference data and calculate the digest 
    1958             if refURI[0] != "#": 
    1959                 raise VerifyError, \ 
    1960                     "Expecting # identifier for Reference URI \"%s\"" % refURI 
    1961                      
    1962             # XPath reference 
    1963             uriXPath = '//*[@wsu:Id="%s"]' % refURI[1:] 
    1964             uriNode = xpath.Evaluate(uriXPath,  
    1965                                      contextNode=parsedSOAP.dom,  
    1966                                      context=ctxt)[0] 
    1967  
    1968             c14nRef = Canonicalize(uriNode, **c14nKw) 
    1969             digestValue = base64.encodestring(sha(c14nRef).digest()).strip() 
    1970              
    1971             # Extract the digest value that was stored             
    1972             digestNode = getElements(refNode, "DigestValue")[0] 
    1973             nodeDigestValue = str(digestNode.childNodes[0].nodeValue).strip()    
    1974              
    1975             # Reference validates if the two digest values are the same 
    1976             if digestValue != nodeDigestValue: 
    1977                 raise VerifyError, \ 
    1978                         'Digest Values do not match for URI: "%s"' % refURI 
     583                'failed to parse exclusive canonicalisation transform: %s' %  
     584                    str(e) 
     585     
     586        # Canonicalize the reference data and calculate the digest 
     587        refC14n = Canonicalize(uriNode, **refC14nKw) 
     588        digestValue = base64.encodestring(sha(refC14n).digest()).strip() 
     589         
     590        # Extract the digest value that was stored             
     591        digestNode = getElements(refNode, "DigestValue")[0] 
     592        nodeDigestValue = str(digestNode.childNodes[0].nodeValue).strip()    
     593         
     594        # Reference validates if the two digest values are the same 
     595        if digestValue != nodeDigestValue: 
     596            raise VerifyError, \ 
     597                    'Digest Values do not match for reference data' 
    1979598                 
    1980599        # 2) Signature Validation 
    1981600        signedInfoNode = xpath.Evaluate('//ds:SignedInfo', 
    1982                                         contextNode=parsedSOAP.dom,  
     601                                        contextNode=self.__docNode,  
    1983602                                        context=ctxt)[0] 
    1984603 
     
    2011630        # calculated 
    2012631        signatureValueNode = xpath.Evaluate('//ds:SignatureValue', 
    2013                                             contextNode=parsedSOAP.dom,  
     632                                            contextNode=self.__docNode,  
    2014633                                            context=ctxt)[0] 
    2015634 
     
    2024643        try: 
    2025644            binSecTokNode = xpath.Evaluate('//wsse:BinarySecurityToken', 
    2026                                            contextNode=parsedSOAP.dom, 
     645                                           contextNode=self.__docNode, 
    2027646                                           context=ctxt)[0] 
    2028647            x509str = binSecTokNode.childNodes[0]._get_nodeValue() 
  • TI12-security/trunk/python/ndg.security.test/ndg/security/test/XMLSecDoc/xmlSecDocTest.cfg

    r1945 r1953  
    1414certFile: ./cert.pem 
    1515keyFile: ./key.pem 
     16filePath: ./ac-signed.xml 
     17#keyPwd: 
    1618 
    1719[test3Write] 
     
    2325[test5Verify] 
    2426certFile: ./cert.pem 
     27filePath: ./ac-signed.xml 
    2528 
    2629 
  • TI12-security/trunk/python/ndg.security.test/ndg/security/test/XMLSecDoc/xmlSecDocTest.py

    r1947 r1953  
    3232 
    3333        self.strXML = """<?xml version="1.0"?> 
    34 <attributeCertificate> 
     34<attributeCertificate targetNamespace="urn:ndg:security"> 
    3535    <acInfo> 
    3636        <version>1.0</version> 
     
    4848                    <name>staff</name> 
    4949                </role> 
    50             <role> 
     50                <role> 
    5151                    <name>postdoc</name> 
    5252                </role> 
    53             <role> 
     53                <role> 
    5454                    <name>academic</name> 
    5555                </role> 
     
    6565        '''test1Parse: parse an XML document''' 
    6666             
    67         try: 
    68             self.xmlSecDoc.parse(self.strXML) 
    69         except: 
    70             self.fail(traceback.print_exc()) 
     67        self.xmlSecDoc.parse(self.strXML) 
     68 
    7169 
    7270    def test2Sign(self):  
    7371        '''test2Sign: sign document''' 
    7472             
    75         try: 
    76             certFilePathList = self.cfg['test2Sign']['certfile'] 
    77             signingKeyFilePath = self.cfg['test2Sign']['keyfile'] 
    78             self.xmlSecDoc.sign() 
    79         except: 
    80             self.fail(traceback.print_exc()) 
     73        self.xmlSecDoc.filePath = self.cfg['test2Sign']['filepath'] 
     74        self.xmlSecDoc.certFilePathList=self.cfg['test2Sign']['certfile'] 
     75        self.xmlSecDoc.signingKeyFilePath=self.cfg['test2Sign']['keyfile'] 
     76         
     77        self.xmlSecDoc.signingKeyPwd = self.cfg['test2Sign'].get('keypwd') or\ 
     78            getpass.getpass(prompt="\ntest2Sign private key password: ") 
     79         
     80        self.xmlSecDoc.sign(xmlTxt=self.strXML) 
     81        self.xmlSecDoc.write() 
     82     
    8183     
    8284    def test3Write(self): 
    8385        '''test3Write: write document''' 
    8486             
    85         try: 
    86             self.xmlSecDoc.filePath = self.cfg['test3Write']['filePath'] 
    87             self.xmlSecDoc.write() 
    88         except: 
    89             self.fail(traceback.print_exc()) 
     87        self.test1Parse() 
     88        self.xmlSecDoc.filePath = self.cfg['test3Write']['filepath'] 
     89        self.xmlSecDoc.write() 
     90       
    9091         
    9192    def test4Read(self): 
    9293        '''test4Read: read document''' 
    9394             
    94         try: 
    95             self.xmlSecDoc.filePath = self.cfg['test4Read'].get('filePath') 
    96             self.xmlSecDoc.read() 
    97         except: 
    98             self.fail(traceback.print_exc()) 
     95        self.xmlSecDoc.filePath = self.cfg['test4Read']['filepath'] 
     96        self.xmlSecDoc.read() 
     97 
    9998 
    10099    def test5Verify(self): 
    101100        '''test5Verify: check signature of XML document''' 
    102101             
    103         try: 
    104             self.xmlSecDoc.verify() 
    105         except: 
    106             self.fail(traceback.print_exc()) 
     102        self.xmlSecDoc.filePath = self.cfg['test5Verify']['filepath'] 
     103        self.xmlSecDoc.certFilePathList=self.cfg['test5Verify']['certfile'] 
     104        self.xmlSecDoc.read() 
     105        self.xmlSecDoc.verify() 
    107106         
    108107  
Note: See TracChangeset for help on using the changeset viewer.