Changeset 2150


Ignore:
Timestamp:
13/02/07 09:56:51 (12 years ago)
Author:
pjkersha
Message:

python/ndg.security.server/ndg/security/server/ca/init.py:

  • Get CA directory from OpenSSLConfig.caDir property
  • re-written chkCAPassphrase so that it uses M2Crypto code rather than a system call to

openssl.

python/ndg.security.common/ndg/security/common/openssl.py: rewritten OpenSSLConfig class
to use SafeConfigParser?. This required an override to allow OpenSSL config file style
querks.

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

Legend:

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

    r2148 r2150  
    1414 
    1515import re, os 
     16from ConfigParser import SafeConfigParser 
    1617 
    1718#_____________________________________________________________________________         
     
    2122 
    2223#_____________________________________________________________________________         
    23 class OpenSSLConfig(object): 
     24class OpenSSLConfig(SafeConfigParser, object): 
    2425    """Wrapper to OpenSSL Configuration file to allow extraction of 
    2526    required distinguished name used for making certificate requests 
    2627     
    27     @cvar __reqDnRE: regular expression pattern for locating required 
    28     distinguished name from the config file 
    29      
     28    @type _certReqDNParamName: tuple 
    3029    @cvar _certReqDNParamName: permissable keys for Distinguished Name 
    3130    (not including CN which gets set separately).  This is used in __setReqDN 
    32     to check input""" 
    33      
    34     __reqDnRE = '\[\s*req_distinguished_name\s*\].*\[' 
    35     
     31    to check input 
     32     
     33    @type _caDirPat: string 
     34    @cvar _caDirPat: sub-directory path to CA config directory 
     35    @type __gridCASubDir: string 
     36    @cvar __gridCASubDir: sub-directory of globus user for CA settings""" 
     37     
    3638    _certReqDNParamName = ('O', 'OU', '0.organizationName', 
    3739                            '0.organizationalUnitName') 
     40     
     41    _caDirPat = re.compile('\$dir') 
     42     
     43    __gridCASubDir = os.path.join(".globus", "simpleCA") 
    3844 
    3945     
     
    4450        @param filePath: path to OpenSSL configuration file""" 
    4551         
    46         # Content of file 
    47         self.__fileTxt = None 
     52        SafeConfigParser.__init__(self) 
     53         
    4854        self.__reqDN = None 
    4955        self.__setFilePath(filePath) 
     56 
     57        # Set-up CA directory 
     58        if not os.environ.get('HOME'): 
     59            raise SimpleCAError, "Environment variable \"HOME\" is not set" 
     60         
     61        self.__caDir = os.path.join(os.environ['HOME'], self.__gridCASubDir) 
    5062 
    5163             
     
    7991                        fset=__setFilePath, 
    8092                        doc="file path for configuration file") 
    81      
    82     def __getFileTxt(self): 
    83         """Get content of file in call to getReqDN 
    84         @rtype: string 
    85         @return: content of file""" 
    86         return self.__fileTxt 
    87      
    88     def __setFileTxt(self, input): 
    89         """Set content of file 
    90         @type input: string 
    91         @param input: content of  file.""" 
    92         if input is not None and not isinstance(input, basestring): 
    93             raise AttributeError, "File text must be string or None type" 
    94          
    95         self.__fileTxt = input 
    96      
    97      
    98     fileTxt = property(fset=__setFileTxt, 
    99                        fget=__getFileTxt, 
    100                        doc="Content of SSL file") 
     93 
     94             
     95    def __setCADir(self, caDir): 
     96        """Set property method 
     97        @param caDir: path for OpenSSL configuration file""" 
     98        if filePath is not None: 
     99            if not isinstance(caDir, basestring): 
     100                raise OpenSSLConfigError, \ 
     101                    "Input OpenSSL CA directory path must be a string" 
     102 
     103            try: 
     104                if not os.access(caDir, os.R_OK): 
     105                    raise OpenSSLConfigError, "not found or no read access" 
     106                                          
     107            except Exception, e: 
     108                raise OpenSSLConfigError, \ 
     109                    "OpenSSL CA directory path is not valid: \"%s\": %s" % \ 
     110                    (filePath, str(e)) 
     111                     
     112        self.__caDir = caDir 
     113                     
     114 
     115    def __getCADir(self): 
     116        """Get property method 
     117        @type caDir: string 
     118        @return caDir: directory path for CA configuration files""" 
     119        return self.__caDir 
     120 
     121    caDir = property(fget=__getCADir, 
     122                     fset=__setCADir, 
     123                     doc="directory path for CA configuration files") 
    101124 
    102125 
     
    106129        @return reqDN: Distinguished Name for certificate request""" 
    107130        return self.__reqDN 
     131 
    108132 
    109133    def __setReqDN(self, reqDN): 
     
    128152                     doc="Distinguished Name for certificate request") 
    129153     
    130         
    131154    def read(self): 
    132         """Read OpenSSL configuration file and parse certificate request 
    133         Distinguished Name settings""" 
    134  
     155        """Override base class version to avoid parsing error with the first 
     156        'RANDFILE = ...' part of the openssl file.  Also, reformat _sections  
     157        to allow for the style of SSL config files where section headings can  
     158        have spaces either side of the brackets e.g.  
     159        [ sectionName ]  
     160         
     161        and comments can occur on the same line as an option e.g.  
     162        option = blah # This is option blah 
     163         
     164        Reformat _sections to """ 
    135165        try: 
    136             self.__fileTxt = open(self.__filePath).read() 
     166            file = open(self.__filePath) 
     167            fileTxt = file.read() 
    137168        except Exception, e: 
    138169            raise OpenSSLConfigError, \ 
    139170                "Error reading OpenSSL config file \"%s\": %s" % \ 
    140171                                                    (self.__filePath, str(e)) 
     172 
     173        idx = re.search('\[\s*\w*\s*\]', fileTxt).span()[0] 
     174        file.seek(idx) 
     175        SafeConfigParser.readfp(self, file) 
     176         
     177        # Filter section names and reomve comments from options 
     178        for section, val in self._sections.items(): 
     179            newSection = section 
     180            self._sections[newSection.strip()] = \ 
     181                                    dict([(opt, self._filtOptVal(optVal)) 
     182                                          for opt, optVal in val.items()]) 
     183            del self._sections[section] 
     184        
     185        self._setReqDN() 
     186 
     187     
     188    def _filtOptVal(self, optVal): 
     189        """For option value, filter out comments and substitute $dir with 
     190        the CA directory location""" 
     191        return self.__class__._caDirPat.sub(self.__caDir, 
     192                                            optVal.split('#')[0].strip()) 
     193 
     194 
     195    def readfp(self, fp): 
     196        """Set to not implemented as using a file object could be problematic 
     197        given read() has to seek ahead to the first actual section to avoid 
     198        parsing errors""" 
     199        raise NotImplementedError, "Use read method instead" 
    141200        self._parseReqDN() 
    142201 
    143202 
    144     def _parseReqDN(self): 
    145         """Parse Required DN parameters from the configuration file returning 
     203    def _setReqDN(self): 
     204        """Set Required DN parameters from the configuration file returning 
    146205        them in a dictionary 
    147206         
     
    150209        # Nb. Match over line boundaries 
    151210        try: 
    152             reqDnTxt = re.findall(self.__reqDnRE, self.__fileTxt, re.S)[0] 
    153  
    154             # Separate lines 
    155             reqDnLines = reqDnTxt.split(os.linesep) 
    156              
    157             # Match the '*_default' entries and make a dictionary 
    158             # 
    159             # Make sure comment lies are omitted - P J Kershaw 22/07/05 
    160             self.__reqDN = dict([re.split('_default\s*=\s*', line) \ 
    161                                  for line in reqDnLines \ 
    162                                  if re.match('[^#].*_default\s*=', line)])  
     211            self.__reqDN = \ 
     212            { 
     213                'O': self.get('req_distinguished_name',  
     214                              '0.organizationName_default'), 
     215                'OU': self.get('req_distinguished_name',  
     216                               '0.organizationalUnitName_default') 
     217            } 
    163218        except Exception, e: 
    164219            raise OpenSSLConfigError, \ 
    165                 "Error parsing content of OpenSSL config file \"%s\: %s" % \ 
     220            'Error setting content of Distinguished Name from file "%s": %s'%\ 
    166221                                                    (self.__filePath, str(e)) 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/ca/__init__.py

    r2148 r2150  
    3131 
    3232# Certificate request generation 
    33 from M2Crypto import X509, RSA, EVP, m2 
     33from M2Crypto import X509, BIO, RSA, EVP, m2 
    3434 
    3535# For parsing of properties file 
     
    5656    @cvar __validKeys: valid configuration property keywords used in file 
    5757    and keyword input to __init__ and setProperties() 
    58      
    59     @type __gridCASubDir: string 
    60     @cvar __gridCASubDir: sub-directory of globus user for CA settings 
    6158     
    6259    @type __gridCAConfigFile: string 
     
    152149 
    153150 
    154         # Set-up CA directory - use in chkCAPassphrase() 
    155         if not os.environ.get('HOME'): 
    156             raise SimpleCAError, "Environment variable \"HOME\" is not set" 
    157          
    158         if 'openSSLConfigFilePath' not in self.__prop:         
    159             self.__openSSLConfig.filePath = os.path.join(os.environ['HOME'],  
    160                                                    self.__gridCASubDir, 
     151        # Make config file path default setting if not already set  
     152        if 'openSSLConfigFilePath' not in self.__prop: 
     153            self.__openSSLConfig.filePath = os.path.join(\ 
     154                                                   self.__openSSLConfig.caDir, 
    161155                                                   self.__gridCAConfigFile) 
    162156            self.__openSSLConfig.read() 
     
    377371 
    378372 
    379     #_________________________________________________________________________ 
    380     def chkCAPassphrase(self, caPassphrase=None): 
     373    def chkCAPassphrase(self, caPassphrase=None):         
     374         
     375        if caPassphrase is None: 
     376            caPassphrase = self.__caPassphrase 
     377        else: 
     378            if not isinstance(caPassphrase, basestring): 
     379                raise SimpleCAPassPhraseError, \ 
     380                                    "CA Pass-phrase must be a valid string" 
     381                                     
     382        try: 
     383            priKeyFilePath = self.__openSSLConfig.get('CA_default',  
     384                                                      'private_key') 
     385            priKeyFile = BIO.File(open(priKeyFilePath)) 
     386             
     387        except Exception, e: 
     388            raise SimpleCAError, \ 
     389                        "Reading private key for pass-phrase check: %s" % e 
     390        try:     
     391            RSA.load_key_bio(priKeyFile,callback=lambda *ar,**kw:caPassphrase) 
     392        except: 
     393            SimpleCAPassPhraseError, "Invalid pass-phrase" 
     394             
     395             
     396    #_________________________________________________________________________ 
     397    def OldchkCAPassphrase(self, caPassphrase=None): 
    381398        """Check given pass-phrase is correct for CA private key 
    382399         
Note: See TracChangeset for help on using the changeset viewer.