source: TI12-security/trunk/python/ndg.security.common/ndg/security/common/openssl.py @ 2150

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg.security.common/ndg/security/common/openssl.py@2150
Revision 2150, 7.8 KB checked in by pjkersha, 14 years ago (diff)

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.

Line 
1"""OpenSSL utilities module - contains OpenSSLConfig class for
2parsing OpenSSL configuration files
3
4NERC Data Grid Project
5
6@author P J Kershaw 08/02/07
7
8@copyright (C) 2007 CCLRC & NERC
9
10@license This software may be distributed under the terms of the Q Public
11License, version 1.0 or later.
12"""
13reposID = '$Id:$'
14
15import re, os
16from ConfigParser import SafeConfigParser
17
18#_____________________________________________________________________________       
19class OpenSSLConfigError(Exception):
20    """Exceptions related to OpenSSLConfig class"""   
21
22
23#_____________________________________________________________________________       
24class OpenSSLConfig(SafeConfigParser, object):
25    """Wrapper to OpenSSL Configuration file to allow extraction of
26    required distinguished name used for making certificate requests
27   
28    @type _certReqDNParamName: tuple
29    @cvar _certReqDNParamName: permissable keys for Distinguished Name
30    (not including CN which gets set separately).  This is used in __setReqDN
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   
38    _certReqDNParamName = ('O', 'OU', '0.organizationName',
39                            '0.organizationalUnitName')
40   
41    _caDirPat = re.compile('\$dir')
42   
43    __gridCASubDir = os.path.join(".globus", "simpleCA")
44
45   
46    def __init__(self, filePath=None):
47        """Initial OpenSSL configuration optionally setting a file path to
48        read from
49       
50        @param filePath: path to OpenSSL configuration file"""
51       
52        SafeConfigParser.__init__(self)
53       
54        self.__reqDN = None
55        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)
62
63           
64    def __setFilePath(self, filePath):
65        """Set property method
66        @param filePath: path for OpenSSL configuration file"""
67        if filePath is not None:
68            if not isinstance(filePath, basestring):
69                raise OpenSSLConfigError, \
70                    "Input OpenSSL config file path must be a string"
71
72            try:
73                if not os.access(filePath, os.R_OK):
74                    raise OpenSSLConfigError, "not found or no read access"
75                                         
76            except Exception, e:
77                raise OpenSSLConfigError, \
78                    "OpenSSL config file path is not valid: \"%s\": %s" % \
79                    (filePath, str(e))
80                   
81        self.__filePath = filePath
82                   
83
84
85    def __getFilePath(self):
86        """Get property method
87        @param filePath: file path for OpenSSL configuration file"""
88        return self.__filePath
89
90    filePath = property(fget=__getFilePath,
91                        fset=__setFilePath,
92                        doc="file path for configuration 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")
124
125
126    def __getReqDN(self):
127        """Get property method
128        @rtype reqDN: dict
129        @return reqDN: Distinguished Name for certificate request"""
130        return self.__reqDN
131
132
133    def __setReqDN(self, reqDN):
134        """Set property method
135        @type reqDN: dict
136        @param reqDN: Distinguished Name for certificate request"""
137        if not isinstance(reqDN, dict):
138            raise AttributeError, "Distinguished Name must be dict type"
139       
140        invalidKw = [k for k in dict \
141                     if k not in self.__class__._certReqDNParamName]
142        if invalidKw:
143            raise AttributeError, \
144    "Invalid certificate request keyword(s): %s.  Valid keywords are: %s" % \
145    (', '.join(invalidKw), ', '.join(self.__class__._certReqDNParamName))
146
147        self.__reqDN = reqDN
148
149
150    reqDN = property(fget=__getReqDN,
151                     fset=__setReqDN,
152                     doc="Distinguished Name for certificate request")
153   
154    def read(self):
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 """
165        try:
166            file = open(self.__filePath)
167            fileTxt = file.read()
168        except Exception, e:
169            raise OpenSSLConfigError, \
170                "Error reading OpenSSL config file \"%s\": %s" % \
171                                                    (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"
200        self._parseReqDN()
201
202
203    def _setReqDN(self):
204        """Set Required DN parameters from the configuration file returning
205        them in a dictionary
206       
207        @return Distinguished Name OU and O defaults in a dictionary"""
208       
209        # Nb. Match over line boundaries
210        try:
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            }
218        except Exception, e:
219            raise OpenSSLConfigError, \
220            'Error setting content of Distinguished Name from file "%s": %s'%\
221                                                    (self.__filePath, str(e))
Note: See TracBrowser for help on using the repository browser.