process: Avoid late failure if /dev/null cannot be opened.
[openvswitch] / xenserver / uuid.py
1 # This file is from Python 2.5.  It has been modified by adding this
2 # license header, which is copied from the LICENSE file distributed
3 # with Python.
4 #
5 # PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
6 # --------------------------------------------
7 #
8 # 1. This LICENSE AGREEMENT is between the Python Software Foundation
9 # ("PSF"), and the Individual or Organization ("Licensee") accessing and
10 # otherwise using this software ("Python") in source or binary form and
11 # its associated documentation.
12 #
13 # 2. Subject to the terms and conditions of this License Agreement, PSF
14 # hereby grants Licensee a nonexclusive, royalty-free, world-wide
15 # license to reproduce, analyze, test, perform and/or display publicly,
16 # prepare derivative works, distribute, and otherwise use Python
17 # alone or in any derivative version, provided, however, that PSF's
18 # License Agreement and PSF's notice of copyright, i.e., "Copyright (c)
19 # 2001, 2002, 2003, 2004, 2005, 2006, 2007 Python Software Foundation;
20 # All Rights Reserved" are retained in Python alone or in any derivative
21 # version prepared by Licensee.
22 #
23 # 3. In the event Licensee prepares a derivative work that is based on
24 # or incorporates Python or any part thereof, and wants to make
25 # the derivative work available to others as provided herein, then
26 # Licensee hereby agrees to include in any such work a brief summary of
27 # the changes made to Python.
28 #
29 # 4. PSF is making Python available to Licensee on an "AS IS"
30 # basis.  PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
31 # IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
32 # DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
33 # FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
34 # INFRINGE ANY THIRD PARTY RIGHTS.
35 #
36 # 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
37 # FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
38 # A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
39 # OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
40 #
41 # 6. This License Agreement will automatically terminate upon a material
42 # breach of its terms and conditions.
43 #
44 # 7. Nothing in this License Agreement shall be deemed to create any
45 # relationship of agency, partnership, or joint venture between PSF and
46 # Licensee.  This License Agreement does not grant permission to use PSF
47 # trademarks or trade name in a trademark sense to endorse or promote
48 # products or services of Licensee, or any third party.
49 #
50 # 8. By copying, installing or otherwise using Python, Licensee
51 # agrees to be bound by the terms and conditions of this License
52 # Agreement.
53
54 r"""UUID objects (universally unique identifiers) according to RFC 4122.
55
56 This module provides immutable UUID objects (class UUID) and the functions
57 uuid1(), uuid3(), uuid4(), uuid5() for generating version 1, 3, 4, and 5
58 UUIDs as specified in RFC 4122.
59
60 If all you want is a unique ID, you should probably call uuid1() or uuid4().
61 Note that uuid1() may compromise privacy since it creates a UUID containing
62 the computer's network address.  uuid4() creates a random UUID.
63
64 Typical usage:
65
66     >>> import uuid
67
68     # make a UUID based on the host ID and current time
69     >>> uuid.uuid1()
70     UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')
71
72     # make a UUID using an MD5 hash of a namespace UUID and a name
73     >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
74     UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
75
76     # make a random UUID
77     >>> uuid.uuid4()
78     UUID('16fd2706-8baf-433b-82eb-8c7fada847da')
79
80     # make a UUID using a SHA-1 hash of a namespace UUID and a name
81     >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
82     UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
83
84     # make a UUID from a string of hex digits (braces and hyphens ignored)
85     >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}')
86
87     # convert a UUID to a string of hex digits in standard form
88     >>> str(x)
89     '00010203-0405-0607-0809-0a0b0c0d0e0f'
90
91     # get the raw 16 bytes of the UUID
92     >>> x.bytes
93     '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'
94
95     # make a UUID from a 16-byte string
96     >>> uuid.UUID(bytes=x.bytes)
97     UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
98 """
99
100 __author__ = 'Ka-Ping Yee <ping@zesty.ca>'
101
102 RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [
103     'reserved for NCS compatibility', 'specified in RFC 4122',
104     'reserved for Microsoft compatibility', 'reserved for future definition']
105
106 class UUID(object):
107     """Instances of the UUID class represent UUIDs as specified in RFC 4122.
108     UUID objects are immutable, hashable, and usable as dictionary keys.
109     Converting a UUID to a string with str() yields something in the form
110     '12345678-1234-1234-1234-123456789abc'.  The UUID constructor accepts
111     five possible forms: a similar string of hexadecimal digits, or a tuple
112     of six integer fields (with 32-bit, 16-bit, 16-bit, 8-bit, 8-bit, and
113     48-bit values respectively) as an argument named 'fields', or a string
114     of 16 bytes (with all the integer fields in big-endian order) as an
115     argument named 'bytes', or a string of 16 bytes (with the first three
116     fields in little-endian order) as an argument named 'bytes_le', or a
117     single 128-bit integer as an argument named 'int'.
118
119     UUIDs have these read-only attributes:
120
121         bytes       the UUID as a 16-byte string (containing the six
122                     integer fields in big-endian byte order)
123
124         bytes_le    the UUID as a 16-byte string (with time_low, time_mid,
125                     and time_hi_version in little-endian byte order)
126
127         fields      a tuple of the six integer fields of the UUID,
128                     which are also available as six individual attributes
129                     and two derived attributes:
130
131             time_low                the first 32 bits of the UUID
132             time_mid                the next 16 bits of the UUID
133             time_hi_version         the next 16 bits of the UUID
134             clock_seq_hi_variant    the next 8 bits of the UUID
135             clock_seq_low           the next 8 bits of the UUID
136             node                    the last 48 bits of the UUID
137
138             time                    the 60-bit timestamp
139             clock_seq               the 14-bit sequence number
140
141         hex         the UUID as a 32-character hexadecimal string
142
143         int         the UUID as a 128-bit integer
144
145         urn         the UUID as a URN as specified in RFC 4122
146
147         variant     the UUID variant (one of the constants RESERVED_NCS,
148                     RFC_4122, RESERVED_MICROSOFT, or RESERVED_FUTURE)
149
150         version     the UUID version number (1 through 5, meaningful only
151                     when the variant is RFC_4122)
152     """
153
154     def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None,
155                        int=None, version=None):
156         r"""Create a UUID from either a string of 32 hexadecimal digits,
157         a string of 16 bytes as the 'bytes' argument, a string of 16 bytes
158         in little-endian order as the 'bytes_le' argument, a tuple of six
159         integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version,
160         8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as
161         the 'fields' argument, or a single 128-bit integer as the 'int'
162         argument.  When a string of hex digits is given, curly braces,
163         hyphens, and a URN prefix are all optional.  For example, these
164         expressions all yield the same UUID:
165
166         UUID('{12345678-1234-5678-1234-567812345678}')
167         UUID('12345678123456781234567812345678')
168         UUID('urn:uuid:12345678-1234-5678-1234-567812345678')
169         UUID(bytes='\x12\x34\x56\x78'*4)
170         UUID(bytes_le='\x78\x56\x34\x12\x34\x12\x78\x56' +
171                       '\x12\x34\x56\x78\x12\x34\x56\x78')
172         UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678))
173         UUID(int=0x12345678123456781234567812345678)
174
175         Exactly one of 'hex', 'bytes', 'bytes_le', 'fields', or 'int' must
176         be given.  The 'version' argument is optional; if given, the resulting
177         UUID will have its variant and version set according to RFC 4122,
178         overriding the given 'hex', 'bytes', 'bytes_le', 'fields', or 'int'.
179         """
180
181         if [hex, bytes, bytes_le, fields, int].count(None) != 4:
182             raise TypeError('need one of hex, bytes, bytes_le, fields, or int')
183         if hex is not None:
184             hex = hex.replace('urn:', '').replace('uuid:', '')
185             hex = hex.strip('{}').replace('-', '')
186             if len(hex) != 32:
187                 raise ValueError('badly formed hexadecimal UUID string')
188             int = long(hex, 16)
189         if bytes_le is not None:
190             if len(bytes_le) != 16:
191                 raise ValueError('bytes_le is not a 16-char string')
192             bytes = (bytes_le[3] + bytes_le[2] + bytes_le[1] + bytes_le[0] +
193                      bytes_le[5] + bytes_le[4] + bytes_le[7] + bytes_le[6] +
194                      bytes_le[8:])
195         if bytes is not None:
196             if len(bytes) != 16:
197                 raise ValueError('bytes is not a 16-char string')
198             int = long(('%02x'*16) % tuple(map(ord, bytes)), 16)
199         if fields is not None:
200             if len(fields) != 6:
201                 raise ValueError('fields is not a 6-tuple')
202             (time_low, time_mid, time_hi_version,
203              clock_seq_hi_variant, clock_seq_low, node) = fields
204             if not 0 <= time_low < 1<<32L:
205                 raise ValueError('field 1 out of range (need a 32-bit value)')
206             if not 0 <= time_mid < 1<<16L:
207                 raise ValueError('field 2 out of range (need a 16-bit value)')
208             if not 0 <= time_hi_version < 1<<16L:
209                 raise ValueError('field 3 out of range (need a 16-bit value)')
210             if not 0 <= clock_seq_hi_variant < 1<<8L:
211                 raise ValueError('field 4 out of range (need an 8-bit value)')
212             if not 0 <= clock_seq_low < 1<<8L:
213                 raise ValueError('field 5 out of range (need an 8-bit value)')
214             if not 0 <= node < 1<<48L:
215                 raise ValueError('field 6 out of range (need a 48-bit value)')
216             clock_seq = (clock_seq_hi_variant << 8L) | clock_seq_low
217             int = ((time_low << 96L) | (time_mid << 80L) |
218                    (time_hi_version << 64L) | (clock_seq << 48L) | node)
219         if int is not None:
220             if not 0 <= int < 1<<128L:
221                 raise ValueError('int is out of range (need a 128-bit value)')
222         if version is not None:
223             if not 1 <= version <= 5:
224                 raise ValueError('illegal version number')
225             # Set the variant to RFC 4122.
226             int &= ~(0xc000 << 48L)
227             int |= 0x8000 << 48L
228             # Set the version number.
229             int &= ~(0xf000 << 64L)
230             int |= version << 76L
231         self.__dict__['int'] = int
232
233     def __cmp__(self, other):
234         if isinstance(other, UUID):
235             return cmp(self.int, other.int)
236         return NotImplemented
237
238     def __hash__(self):
239         return hash(self.int)
240
241     def __int__(self):
242         return self.int
243
244     def __repr__(self):
245         return 'UUID(%r)' % str(self)
246
247     def __setattr__(self, name, value):
248         raise TypeError('UUID objects are immutable')
249
250     def __str__(self):
251         hex = '%032x' % self.int
252         return '%s-%s-%s-%s-%s' % (
253             hex[:8], hex[8:12], hex[12:16], hex[16:20], hex[20:])
254
255     def get_bytes(self):
256         bytes = ''
257         for shift in range(0, 128, 8):
258             bytes = chr((self.int >> shift) & 0xff) + bytes
259         return bytes
260
261     bytes = property(get_bytes)
262
263     def get_bytes_le(self):
264         bytes = self.bytes
265         return (bytes[3] + bytes[2] + bytes[1] + bytes[0] +
266                 bytes[5] + bytes[4] + bytes[7] + bytes[6] + bytes[8:])
267
268     bytes_le = property(get_bytes_le)
269
270     def get_fields(self):
271         return (self.time_low, self.time_mid, self.time_hi_version,
272                 self.clock_seq_hi_variant, self.clock_seq_low, self.node)
273
274     fields = property(get_fields)
275
276     def get_time_low(self):
277         return self.int >> 96L
278
279     time_low = property(get_time_low)
280
281     def get_time_mid(self):
282         return (self.int >> 80L) & 0xffff
283
284     time_mid = property(get_time_mid)
285
286     def get_time_hi_version(self):
287         return (self.int >> 64L) & 0xffff
288
289     time_hi_version = property(get_time_hi_version)
290
291     def get_clock_seq_hi_variant(self):
292         return (self.int >> 56L) & 0xff
293
294     clock_seq_hi_variant = property(get_clock_seq_hi_variant)
295
296     def get_clock_seq_low(self):
297         return (self.int >> 48L) & 0xff
298
299     clock_seq_low = property(get_clock_seq_low)
300
301     def get_time(self):
302         return (((self.time_hi_version & 0x0fffL) << 48L) |
303                 (self.time_mid << 32L) | self.time_low)
304
305     time = property(get_time)
306
307     def get_clock_seq(self):
308         return (((self.clock_seq_hi_variant & 0x3fL) << 8L) |
309                 self.clock_seq_low)
310
311     clock_seq = property(get_clock_seq)
312
313     def get_node(self):
314         return self.int & 0xffffffffffff
315
316     node = property(get_node)
317
318     def get_hex(self):
319         return '%032x' % self.int
320
321     hex = property(get_hex)
322
323     def get_urn(self):
324         return 'urn:uuid:' + str(self)
325
326     urn = property(get_urn)
327
328     def get_variant(self):
329         if not self.int & (0x8000 << 48L):
330             return RESERVED_NCS
331         elif not self.int & (0x4000 << 48L):
332             return RFC_4122
333         elif not self.int & (0x2000 << 48L):
334             return RESERVED_MICROSOFT
335         else:
336             return RESERVED_FUTURE
337
338     variant = property(get_variant)
339
340     def get_version(self):
341         # The version bits are only meaningful for RFC 4122 UUIDs.
342         if self.variant == RFC_4122:
343             return int((self.int >> 76L) & 0xf)
344
345     version = property(get_version)
346
347 def _find_mac(command, args, hw_identifiers, get_index):
348     import os
349     for dir in ['', '/sbin/', '/usr/sbin']:
350         executable = os.path.join(dir, command)
351         if not os.path.exists(executable):
352             continue
353
354         try:
355             # LC_ALL to get English output, 2>/dev/null to
356             # prevent output on stderr
357             cmd = 'LC_ALL=C %s %s 2>/dev/null' % (executable, args)
358             pipe = os.popen(cmd)
359         except IOError:
360             continue
361
362         for line in pipe:
363             words = line.lower().split()
364             for i in range(len(words)):
365                 if words[i] in hw_identifiers:
366                     return int(words[get_index(i)].replace(':', ''), 16)
367     return None
368
369 def _ifconfig_getnode():
370     """Get the hardware address on Unix by running ifconfig."""
371
372     # This works on Linux ('' or '-a'), Tru64 ('-av'), but not all Unixes.
373     for args in ('', '-a', '-av'):
374         mac = _find_mac('ifconfig', args, ['hwaddr', 'ether'], lambda i: i+1)
375         if mac:
376             return mac
377
378     import socket
379     ip_addr = socket.gethostbyname(socket.gethostname())
380
381     # Try getting the MAC addr from arp based on our IP address (Solaris).
382     mac = _find_mac('arp', '-an', [ip_addr], lambda i: -1)
383     if mac:
384         return mac
385
386     # This might work on HP-UX.
387     mac = _find_mac('lanscan', '-ai', ['lan0'], lambda i: 0)
388     if mac:
389         return mac
390
391     return None
392
393 def _ipconfig_getnode():
394     """Get the hardware address on Windows by running ipconfig.exe."""
395     import os, re
396     dirs = ['', r'c:\windows\system32', r'c:\winnt\system32']
397     try:
398         import ctypes
399         buffer = ctypes.create_string_buffer(300)
400         ctypes.windll.kernel32.GetSystemDirectoryA(buffer, 300)
401         dirs.insert(0, buffer.value.decode('mbcs'))
402     except:
403         pass
404     for dir in dirs:
405         try:
406             pipe = os.popen(os.path.join(dir, 'ipconfig') + ' /all')
407         except IOError:
408             continue
409         for line in pipe:
410             value = line.split(':')[-1].strip().lower()
411             if re.match('([0-9a-f][0-9a-f]-){5}[0-9a-f][0-9a-f]', value):
412                 return int(value.replace('-', ''), 16)
413
414 def _netbios_getnode():
415     """Get the hardware address on Windows using NetBIOS calls.
416     See http://support.microsoft.com/kb/118623 for details."""
417     import win32wnet, netbios
418     ncb = netbios.NCB()
419     ncb.Command = netbios.NCBENUM
420     ncb.Buffer = adapters = netbios.LANA_ENUM()
421     adapters._pack()
422     if win32wnet.Netbios(ncb) != 0:
423         return
424     adapters._unpack()
425     for i in range(adapters.length):
426         ncb.Reset()
427         ncb.Command = netbios.NCBRESET
428         ncb.Lana_num = ord(adapters.lana[i])
429         if win32wnet.Netbios(ncb) != 0:
430             continue
431         ncb.Reset()
432         ncb.Command = netbios.NCBASTAT
433         ncb.Lana_num = ord(adapters.lana[i])
434         ncb.Callname = '*'.ljust(16)
435         ncb.Buffer = status = netbios.ADAPTER_STATUS()
436         if win32wnet.Netbios(ncb) != 0:
437             continue
438         status._unpack()
439         bytes = map(ord, status.adapter_address)
440         return ((bytes[0]<<40L) + (bytes[1]<<32L) + (bytes[2]<<24L) +
441                 (bytes[3]<<16L) + (bytes[4]<<8L) + bytes[5])
442
443 # Thanks to Thomas Heller for ctypes and for his help with its use here.
444
445 # If ctypes is available, use it to find system routines for UUID generation.
446 _uuid_generate_random = _uuid_generate_time = _UuidCreate = None
447 try:
448     import ctypes, ctypes.util
449     _buffer = ctypes.create_string_buffer(16)
450
451     # The uuid_generate_* routines are provided by libuuid on at least
452     # Linux and FreeBSD, and provided by libc on Mac OS X.
453     for libname in ['uuid', 'c']:
454         try:
455             lib = ctypes.CDLL(ctypes.util.find_library(libname))
456         except:
457             continue
458         if hasattr(lib, 'uuid_generate_random'):
459             _uuid_generate_random = lib.uuid_generate_random
460         if hasattr(lib, 'uuid_generate_time'):
461             _uuid_generate_time = lib.uuid_generate_time
462
463     # On Windows prior to 2000, UuidCreate gives a UUID containing the
464     # hardware address.  On Windows 2000 and later, UuidCreate makes a
465     # random UUID and UuidCreateSequential gives a UUID containing the
466     # hardware address.  These routines are provided by the RPC runtime.
467     # NOTE:  at least on Tim's WinXP Pro SP2 desktop box, while the last
468     # 6 bytes returned by UuidCreateSequential are fixed, they don't appear
469     # to bear any relationship to the MAC address of any network device
470     # on the box.
471     try:
472         lib = ctypes.windll.rpcrt4
473     except:
474         lib = None
475     _UuidCreate = getattr(lib, 'UuidCreateSequential',
476                           getattr(lib, 'UuidCreate', None))
477 except:
478     pass
479
480 def _unixdll_getnode():
481     """Get the hardware address on Unix using ctypes."""
482     _uuid_generate_time(_buffer)
483     return UUID(bytes=_buffer.raw).node
484
485 def _windll_getnode():
486     """Get the hardware address on Windows using ctypes."""
487     if _UuidCreate(_buffer) == 0:
488         return UUID(bytes=_buffer.raw).node
489
490 def _random_getnode():
491     """Get a random node ID, with eighth bit set as suggested by RFC 4122."""
492     import random
493     return random.randrange(0, 1<<48L) | 0x010000000000L
494
495 _node = None
496
497 def getnode():
498     """Get the hardware address as a 48-bit positive integer.
499
500     The first time this runs, it may launch a separate program, which could
501     be quite slow.  If all attempts to obtain the hardware address fail, we
502     choose a random 48-bit number with its eighth bit set to 1 as recommended
503     in RFC 4122.
504     """
505
506     global _node
507     if _node is not None:
508         return _node
509
510     import sys
511     if sys.platform == 'win32':
512         getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
513     else:
514         getters = [_unixdll_getnode, _ifconfig_getnode]
515
516     for getter in getters + [_random_getnode]:
517         try:
518             _node = getter()
519         except:
520             continue
521         if _node is not None:
522             return _node
523
524 _last_timestamp = None
525
526 def uuid1(node=None, clock_seq=None):
527     """Generate a UUID from a host ID, sequence number, and the current time.
528     If 'node' is not given, getnode() is used to obtain the hardware
529     address.  If 'clock_seq' is given, it is used as the sequence number;
530     otherwise a random 14-bit sequence number is chosen."""
531
532     # When the system provides a version-1 UUID generator, use it (but don't
533     # use UuidCreate here because its UUIDs don't conform to RFC 4122).
534     if _uuid_generate_time and node is clock_seq is None:
535         _uuid_generate_time(_buffer)
536         return UUID(bytes=_buffer.raw)
537
538     global _last_timestamp
539     import time
540     nanoseconds = int(time.time() * 1e9)
541     # 0x01b21dd213814000 is the number of 100-ns intervals between the
542     # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
543     timestamp = int(nanoseconds/100) + 0x01b21dd213814000L
544     if timestamp <= _last_timestamp:
545         timestamp = _last_timestamp + 1
546     _last_timestamp = timestamp
547     if clock_seq is None:
548         import random
549         clock_seq = random.randrange(1<<14L) # instead of stable storage
550     time_low = timestamp & 0xffffffffL
551     time_mid = (timestamp >> 32L) & 0xffffL
552     time_hi_version = (timestamp >> 48L) & 0x0fffL
553     clock_seq_low = clock_seq & 0xffL
554     clock_seq_hi_variant = (clock_seq >> 8L) & 0x3fL
555     if node is None:
556         node = getnode()
557     return UUID(fields=(time_low, time_mid, time_hi_version,
558                         clock_seq_hi_variant, clock_seq_low, node), version=1)
559
560 def uuid3(namespace, name):
561     """Generate a UUID from the MD5 hash of a namespace UUID and a name."""
562     import md5
563     hash = md5.md5(namespace.bytes + name).digest()
564     return UUID(bytes=hash[:16], version=3)
565
566 def uuid4():
567     """Generate a random UUID."""
568
569     # When the system provides a version-4 UUID generator, use it.
570     if _uuid_generate_random:
571         _uuid_generate_random(_buffer)
572         return UUID(bytes=_buffer.raw)
573
574     # Otherwise, get randomness from urandom or the 'random' module.
575     try:
576         import os
577         return UUID(bytes=os.urandom(16), version=4)
578     except:
579         import random
580         bytes = [chr(random.randrange(256)) for i in range(16)]
581         return UUID(bytes=bytes, version=4)
582
583 def uuid5(namespace, name):
584     """Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
585     import sha
586     hash = sha.sha(namespace.bytes + name).digest()
587     return UUID(bytes=hash[:16], version=5)
588
589 # The following standard UUIDs are for use with uuid3() or uuid5().
590
591 NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
592 NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8')
593 NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8')
594 NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8')