Package contrail :: Package security :: Package onlineca :: Package client :: Module openssl_utils
[hide private]

Source Code for Module contrail.security.onlineca.client.openssl_utils

  1  """Online CA OpenSSL utilities module 
  2   
  3  Contrail Project 
  4  """ 
  5  __author__ = "P J Kershaw" 
  6  __date__ = "24/09/12" 
  7  __copyright__ = "(C) 2012 Science and Technology Facilities Council" 
  8  __license__ = "BSD - see LICENSE file in top-level directory" 
  9  __contact__ = "Philip.Kershaw@stfc.ac.uk" 
 10  __revision__ = '$Id$' 
 11  import re 
 12   
 13  from OpenSSL import crypto 
14 15 16 -class X509SubjectNameError(Exception):
17 '''Base class for X509SubjectName class errors'''
18
19 20 -class X509SubjectNameParseError(X509SubjectNameError):
21 '''Parsing error for X509SubjectName class'''
22
23 24 -class X509SubjectNameConfigError(X509SubjectNameError):
25 '''Configuration related error for X509SubjectName class'''
26
27 28 -class X509SubjectName(object):
29 '''Class to handle X.509 subject names''' 30 SHORT_NAME_LOOKUP = { 31 'commonName': 'CN', 32 'organisationalUnitName': 'OU', 33 'organisation': 'O', 34 'countryName': 'C', 35 'emailAddress': 'EMAILADDRESS', 36 'localityName': 'L', 37 'stateOrProvinceName': 'ST', 38 'streetAddress': 'STREET', 39 'domainComponent': 'DC', 40 'userid': 'UID' 41 } 42 SLASH_PARSER_RE_STR = '/(%s)=' % '|'.join(SHORT_NAME_LOOKUP.keys() + 43 SHORT_NAME_LOOKUP.values()) 44 SLASH_PARSER_RE = re.compile(SLASH_PARSER_RE_STR) 45 46 COMMA_PARSER_RE_STR = '[,]?\s*(%s)=' % '|'.join(SHORT_NAME_LOOKUP.keys() + 47 SHORT_NAME_LOOKUP.values()) 48 COMMA_PARSER_RE = re.compile(COMMA_PARSER_RE_STR) 49 50 VALID_SEPARATORS = ('/', ',') 51
52 - def __init__(self):
53 self._dn = {}
54 55 @classmethod
56 - def from_string(cls, dn, separator=None):
57 obj = cls() 58 obj._dn = cls.parse(dn, separator) 59 60 return obj
61 62 @classmethod
63 - def parse(cls, dn, separator=None):
64 '''Parse string distinguished name into a dictionary for fields. Where 65 multiple entries exist for a field, values are set as a tuple 66 ''' 67 if separator in ('/', None): 68 parser_re = cls.SLASH_PARSER_RE 69 elif separator == ',': 70 parser_re = cls.COMMA_PARSER_RE 71 else: 72 raise X509SubjectNameConfigError('Invalid field separator %r' % 73 separator) 74 75 dn_fields = parser_re.split(dn) 76 if len(dn_fields) < 2: 77 raise X509SubjectNameConfigError('Error parsing DN string: \"%s\"' % 78 dn) 79 80 items = zip(dn_fields[1::2], dn_fields[2::2]) 81 82 # Strip leading and trailing space chars and convert into a 83 # dictionary 84 parsed_dn = {} 85 for key, val in items: 86 key = key.strip() 87 if key in parsed_dn: 88 if isinstance(parsed_dn[key], tuple): 89 parsed_dn[key] = tuple(list(parsed_dn[key]) + [val]) 90 else: 91 parsed_dn[key] = (parsed_dn[key], val) 92 else: 93 parsed_dn[key] = val 94 95 return parsed_dn
96
97 - def serialize(self, *args, **kwargs):
98 '''Serialize subject name iterable into a string''' 99 return self.__class__.Serialize(self._dn, *args, **kwargs)
100 101 @classmethod
102 - def Serialize(cls, dn, separator='/', sort=True):
103 '''Classmethod implementation - Serialize subject name iterable into a 104 string''' 105 106 if separator not in cls.VALID_SEPARATORS: 107 raise X509SubjectNameConfigError('Invalid field separator %r' % 108 separator) 109 110 # If using '/' then prepend DN with an initial '/' char 111 if separator == '/': 112 s_dn = separator 113 else: 114 s_dn = '' 115 116 dn_list = [] 117 for key, val in dn.items(): 118 if val: 119 if isinstance(val, tuple): 120 kv_pairs = ["%s=%s" % (key, val_sub) for val_sub in val] 121 dn_list += [separator.join(kv_pairs)] 122 else: 123 dn_list += ["%s=%s" % (key, val)] 124 125 if sort: 126 dn_list.sort() 127 128 s_dn += separator.join(dn_list) 129 130 return s_dn
131
133 '''@return: this object as an OpenSSL package equivalent type 134 @rtype: OpenSSL.crypto.X509Name 135 ''' 136 subject_name = crypto.X509().get_subject() 137 for k, v in self._dn.items(): 138 if isinstance(v, tuple): 139 # Ugly hack to get around problem that PyOpenSSL X509Name 140 # interface doesn't allowing the setting of multiple values for 141 # the same DN component 142 _v = v[0] + '/' + '/'.join(["%s=%s" % (k, i) for i in v[1:]]) 143 setattr(subject_name, k, _v) 144 else: 145 setattr(subject_name, k, v) 146 147 return subject_name
148