Hello community, here is the log from the commit of package python-asn1crypto for openSUSE:Factory checked in at 2017-12-21 11:23:48 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-asn1crypto (Old) and /work/SRC/openSUSE:Factory/.python-asn1crypto.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-asn1crypto" Thu Dec 21 11:23:48 2017 rev:4 rq:557782 version:0.24.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-asn1crypto/python-asn1crypto.changes 2017-11-17 10:35:56.293572837 +0100 +++ /work/SRC/openSUSE:Factory/.python-asn1crypto.new/python-asn1crypto.changes 2017-12-21 11:23:55.919381282 +0100 @@ -1,0 +2,22 @@ +Sat Dec 16 23:08:43 UTC 2017 - [email protected] + +- update to version 0.24.0: + * x509.Certificate().self_signed will no longer return "yes" under + any circumstances. This helps prevent confusion since the library + does not verify the signature. Instead a library like oscrypto + should be used to confirm if a certificate is self-signed. + * Added various OIDs to x509.KeyPurposeId() + * Added x509.Certificate().private_key_usage_period_value + * Added structures for parsing common subject directory attributes + for X.509 certificates, including x509.SubjectDirectoryAttribute() + * Added algos.AnyAlgorithmIdentifier() for situations where an + algorithm identifier may contain a digest, signed digest or + encryption algorithm OID + * Fixed a bug with + x509.Certificate().subject_directory_attributes_value not + returning the correct value + * Fixed a bug where explicitly-tagged fields in a core.Sequence() + would not function properly when the field had a default value + * Fixed a bug with type checking in pem.armor() + +------------------------------------------------------------------- Old: ---- asn1crypto-0.23.0.tar.gz New: ---- asn1crypto-0.24.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-asn1crypto.spec ++++++ --- /var/tmp/diff_new_pack.g8Kdv4/_old 2017-12-21 11:23:58.563252368 +0100 +++ /var/tmp/diff_new_pack.g8Kdv4/_new 2017-12-21 11:23:58.567252173 +0100 @@ -19,7 +19,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %bcond_without test Name: python-asn1crypto -Version: 0.23.0 +Version: 0.24.0 Release: 0 Summary: ASN.1 parser and serializer for Python License: MIT ++++++ asn1crypto-0.23.0.tar.gz -> asn1crypto-0.24.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asn1crypto-0.23.0/PKG-INFO new/asn1crypto-0.24.0/PKG-INFO --- old/asn1crypto-0.23.0/PKG-INFO 2017-09-22 22:36:35.000000000 +0200 +++ new/asn1crypto-0.24.0/PKG-INFO 2017-12-14 22:04:10.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: asn1crypto -Version: 0.23.0 +Version: 0.24.0 Summary: Fast ASN.1 parser and serializer with definitions for private keys, public keys, certificates, CRL, OCSP, CMS, PKCS#3, PKCS#7, PKCS#8, PKCS#12, PKCS#5, X.509 and TSP Home-page: https://github.com/wbond/asn1crypto Author: wbond diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asn1crypto-0.23.0/asn1crypto/_elliptic_curve.py new/asn1crypto-0.24.0/asn1crypto/_elliptic_curve.py --- old/asn1crypto-0.23.0/asn1crypto/_elliptic_curve.py 2016-06-16 11:12:23.000000000 +0200 +++ new/asn1crypto-0.24.0/asn1crypto/_elliptic_curve.py 2017-11-07 22:32:35.000000000 +0100 @@ -160,10 +160,10 @@ p = self.curve.p - l = ((other.y - self.y) * inverse_mod(other.x - self.x, p)) % p + l_ = ((other.y - self.y) * inverse_mod(other.x - self.x, p)) % p - x3 = (l * l - self.x - other.x) % p - y3 = (l * (self.x - x3) - self.y) % p + x3 = (l_ * l_ - self.x - other.x) % p + y3 = (l_ * (self.x - x3) - self.y) % p return PrimePoint(self.curve, x3, y3) @@ -232,10 +232,10 @@ p = self.curve.p a = self.curve.a - l = ((3 * self.x * self.x + a) * inverse_mod(2 * self.y, p)) % p + l_ = ((3 * self.x * self.x + a) * inverse_mod(2 * self.y, p)) % p - x3 = (l * l - 2 * self.x) % p - y3 = (l * (self.x - x3) - self.y) % p + x3 = (l_ * l_ - 2 * self.x) % p + y3 = (l_ * (self.x - x3) - self.y) % p return PrimePoint(self.curve, x3, y3) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asn1crypto-0.23.0/asn1crypto/_inet.py new/asn1crypto-0.24.0/asn1crypto/_inet.py --- old/asn1crypto-0.23.0/asn1crypto/_inet.py 2017-08-04 16:22:28.000000000 +0200 +++ new/asn1crypto-0.24.0/asn1crypto/_inet.py 2017-11-07 22:09:57.000000000 +0100 @@ -1,170 +1,170 @@ -# coding: utf-8 -from __future__ import unicode_literals, division, absolute_import, print_function - -import socket -import struct - -from ._errors import unwrap -from ._types import byte_cls, bytes_to_list, str_cls, type_name - - -def inet_ntop(address_family, packed_ip): - """ - Windows compatibility shim for socket.inet_ntop(). - - :param address_family: - socket.AF_INET for IPv4 or socket.AF_INET6 for IPv6 - - :param packed_ip: - A byte string of the network form of an IP address - - :return: - A unicode string of the IP address - """ - - if address_family not in set([socket.AF_INET, socket.AF_INET6]): - raise ValueError(unwrap( - ''' - address_family must be socket.AF_INET (%s) or socket.AF_INET6 (%s), - not %s - ''', - repr(socket.AF_INET), - repr(socket.AF_INET6), - repr(address_family) - )) - - if not isinstance(packed_ip, byte_cls): - raise TypeError(unwrap( - ''' - packed_ip must be a byte string, not %s - ''', - type_name(packed_ip) - )) - - required_len = 4 if address_family == socket.AF_INET else 16 - if len(packed_ip) != required_len: - raise ValueError(unwrap( - ''' - packed_ip must be %d bytes long - is %d - ''', - required_len, - len(packed_ip) - )) - - if address_family == socket.AF_INET: - return '%d.%d.%d.%d' % tuple(bytes_to_list(packed_ip)) - - octets = struct.unpack(b'!HHHHHHHH', packed_ip) - - runs_of_zero = {} - longest_run = 0 - zero_index = None - for i, octet in enumerate(octets + (-1,)): - if octet != 0: - if zero_index is not None: - length = i - zero_index - if length not in runs_of_zero: - runs_of_zero[length] = zero_index - longest_run = max(longest_run, length) - zero_index = None - elif zero_index is None: - zero_index = i - - hexed = [hex(o)[2:] for o in octets] - - if longest_run < 2: - return ':'.join(hexed) - - zero_start = runs_of_zero[longest_run] - zero_end = zero_start + longest_run - - return ':'.join(hexed[:zero_start]) + '::' + ':'.join(hexed[zero_end:]) - - -def inet_pton(address_family, ip_string): - """ - Windows compatibility shim for socket.inet_ntop(). - - :param address_family: - socket.AF_INET for IPv4 or socket.AF_INET6 for IPv6 - - :param ip_string: - A unicode string of an IP address - - :return: - A byte string of the network form of the IP address - """ - - if address_family not in set([socket.AF_INET, socket.AF_INET6]): - raise ValueError(unwrap( - ''' - address_family must be socket.AF_INET (%s) or socket.AF_INET6 (%s), - not %s - ''', - repr(socket.AF_INET), - repr(socket.AF_INET6), - repr(address_family) - )) - - if not isinstance(ip_string, str_cls): - raise TypeError(unwrap( - ''' - ip_string must be a unicode string, not %s - ''', - type_name(ip_string) - )) - - if address_family == socket.AF_INET: - octets = ip_string.split('.') - error = len(octets) != 4 - if not error: - ints = [] - for o in octets: - o = int(o) - if o > 255 or o < 0: - error = True - break - ints.append(o) - - if error: - raise ValueError(unwrap( - ''' - ip_string must be a dotted string with four integers in the - range of 0 to 255, got %s - ''', - repr(ip_string) - )) - - return struct.pack(b'!BBBB', *ints) - - error = False - omitted = ip_string.count('::') - if omitted > 1: - error = True - elif omitted == 0: - octets = ip_string.split(':') - error = len(octets) != 8 - else: - begin, end = ip_string.split('::') - begin_octets = begin.split(':') - end_octets = end.split(':') - missing = 8 - len(begin_octets) - len(end_octets) - octets = begin_octets + (['0'] * missing) + end_octets - - if not error: - ints = [] - for o in octets: - o = int(o, 16) - if o > 65535 or o < 0: - error = True - break - ints.append(o) - - return struct.pack(b'!HHHHHHHH', *ints) - - raise ValueError(unwrap( - ''' - ip_string must be a valid ipv6 string, got %s - ''', - repr(ip_string) - )) +# coding: utf-8 +from __future__ import unicode_literals, division, absolute_import, print_function + +import socket +import struct + +from ._errors import unwrap +from ._types import byte_cls, bytes_to_list, str_cls, type_name + + +def inet_ntop(address_family, packed_ip): + """ + Windows compatibility shim for socket.inet_ntop(). + + :param address_family: + socket.AF_INET for IPv4 or socket.AF_INET6 for IPv6 + + :param packed_ip: + A byte string of the network form of an IP address + + :return: + A unicode string of the IP address + """ + + if address_family not in set([socket.AF_INET, socket.AF_INET6]): + raise ValueError(unwrap( + ''' + address_family must be socket.AF_INET (%s) or socket.AF_INET6 (%s), + not %s + ''', + repr(socket.AF_INET), + repr(socket.AF_INET6), + repr(address_family) + )) + + if not isinstance(packed_ip, byte_cls): + raise TypeError(unwrap( + ''' + packed_ip must be a byte string, not %s + ''', + type_name(packed_ip) + )) + + required_len = 4 if address_family == socket.AF_INET else 16 + if len(packed_ip) != required_len: + raise ValueError(unwrap( + ''' + packed_ip must be %d bytes long - is %d + ''', + required_len, + len(packed_ip) + )) + + if address_family == socket.AF_INET: + return '%d.%d.%d.%d' % tuple(bytes_to_list(packed_ip)) + + octets = struct.unpack(b'!HHHHHHHH', packed_ip) + + runs_of_zero = {} + longest_run = 0 + zero_index = None + for i, octet in enumerate(octets + (-1,)): + if octet != 0: + if zero_index is not None: + length = i - zero_index + if length not in runs_of_zero: + runs_of_zero[length] = zero_index + longest_run = max(longest_run, length) + zero_index = None + elif zero_index is None: + zero_index = i + + hexed = [hex(o)[2:] for o in octets] + + if longest_run < 2: + return ':'.join(hexed) + + zero_start = runs_of_zero[longest_run] + zero_end = zero_start + longest_run + + return ':'.join(hexed[:zero_start]) + '::' + ':'.join(hexed[zero_end:]) + + +def inet_pton(address_family, ip_string): + """ + Windows compatibility shim for socket.inet_ntop(). + + :param address_family: + socket.AF_INET for IPv4 or socket.AF_INET6 for IPv6 + + :param ip_string: + A unicode string of an IP address + + :return: + A byte string of the network form of the IP address + """ + + if address_family not in set([socket.AF_INET, socket.AF_INET6]): + raise ValueError(unwrap( + ''' + address_family must be socket.AF_INET (%s) or socket.AF_INET6 (%s), + not %s + ''', + repr(socket.AF_INET), + repr(socket.AF_INET6), + repr(address_family) + )) + + if not isinstance(ip_string, str_cls): + raise TypeError(unwrap( + ''' + ip_string must be a unicode string, not %s + ''', + type_name(ip_string) + )) + + if address_family == socket.AF_INET: + octets = ip_string.split('.') + error = len(octets) != 4 + if not error: + ints = [] + for o in octets: + o = int(o) + if o > 255 or o < 0: + error = True + break + ints.append(o) + + if error: + raise ValueError(unwrap( + ''' + ip_string must be a dotted string with four integers in the + range of 0 to 255, got %s + ''', + repr(ip_string) + )) + + return struct.pack(b'!BBBB', *ints) + + error = False + omitted = ip_string.count('::') + if omitted > 1: + error = True + elif omitted == 0: + octets = ip_string.split(':') + error = len(octets) != 8 + else: + begin, end = ip_string.split('::') + begin_octets = begin.split(':') + end_octets = end.split(':') + missing = 8 - len(begin_octets) - len(end_octets) + octets = begin_octets + (['0'] * missing) + end_octets + + if not error: + ints = [] + for o in octets: + o = int(o, 16) + if o > 65535 or o < 0: + error = True + break + ints.append(o) + + return struct.pack(b'!HHHHHHHH', *ints) + + raise ValueError(unwrap( + ''' + ip_string must be a valid ipv6 string, got %s + ''', + repr(ip_string) + )) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asn1crypto-0.23.0/asn1crypto/algos.py new/asn1crypto-0.24.0/asn1crypto/algos.py --- old/asn1crypto-0.23.0/asn1crypto/algos.py 2017-09-15 12:45:30.000000000 +0200 +++ new/asn1crypto-0.24.0/asn1crypto/algos.py 2017-11-22 17:10:10.000000000 +0100 @@ -5,6 +5,7 @@ key cryptography. Exports the following items: - AlgorithmIdentifier() + - AnyAlgorithmIdentifier() - DigestAlgorithm() - DigestInfo() - DSASignature() @@ -1113,3 +1114,30 @@ EncryptionAlgorithm._oid_specs['pbes2'] = Pbes2Params + + +class AnyAlgorithmId(ObjectIdentifier): + _map = {} + + def _setup(self): + _map = self.__class__._map + for other_cls in (EncryptionAlgorithmId, SignedDigestAlgorithmId, DigestAlgorithmId): + for oid, name in other_cls._map.items(): + _map[oid] = name + + +class AnyAlgorithmIdentifier(_ForceNullParameters, Sequence): + _fields = [ + ('algorithm', AnyAlgorithmId), + ('parameters', Any, {'optional': True}), + ] + + _oid_pair = ('algorithm', 'parameters') + _oid_specs = {} + + def _setup(self): + Sequence._setup(self) + specs = self.__class__._oid_specs + for other_cls in (EncryptionAlgorithm, SignedDigestAlgorithm): + for oid, spec in other_cls._oid_specs.items(): + specs[oid] = spec diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asn1crypto-0.23.0/asn1crypto/cms.py new/asn1crypto-0.24.0/asn1crypto/cms.py --- old/asn1crypto-0.23.0/asn1crypto/cms.py 2017-09-15 12:51:05.000000000 +0200 +++ new/asn1crypto-0.24.0/asn1crypto/cms.py 2017-11-20 13:22:36.000000000 +0100 @@ -15,6 +15,8 @@ - SignedData() Other type classes are defined that help compose the types listed above. + +Most CMS structures in the wild are formatted as ContentInfo encapsulating one of the other types. """ from __future__ import unicode_literals, division, absolute_import, print_function diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asn1crypto-0.23.0/asn1crypto/core.py new/asn1crypto-0.24.0/asn1crypto/core.py --- old/asn1crypto-0.23.0/asn1crypto/core.py 2017-09-15 13:20:50.000000000 +0200 +++ new/asn1crypto-0.24.0/asn1crypto/core.py 2017-11-21 18:02:30.000000000 +0100 @@ -5029,15 +5029,14 @@ # If an explicit specification was passed in, make sure it matches if spec is not None: - if spec_params: - value = spec(contents=contents, **spec_params) - else: - value = spec(contents=contents) - - if spec is Any: - pass - - elif value.explicit: + # If there is explicit tagging and contents, we have to split + # the header and trailer off before we do the parsing + no_explicit = spec_params and 'no_explicit' in spec_params + if not no_explicit and (spec.explicit or (spec_params and 'explicit' in spec_params)): + if spec_params: + value = spec(**spec_params) + else: + value = spec() original_explicit = value.explicit explicit_info = reversed(original_explicit) parsed_class = class_ @@ -5081,60 +5080,69 @@ parsed_class, parsed_method, parsed_tag, parsed_header, to_parse, parsed_trailer = info explicit_header += parsed_header explicit_trailer = parsed_trailer + explicit_trailer + value = _build(*info, spec=spec, spec_params={'no_explicit': True}) value._header = explicit_header value._trailer = explicit_trailer value.explicit = original_explicit header_set = True - - elif isinstance(value, Choice): - value.validate(class_, tag, contents) - try: - # Force parsing the Choice now - value.contents = header + value.contents - header = b'' - value.parse() - except (ValueError, TypeError) as e: - args = e.args[1:] - e.args = (e.args[0] + '\n while parsing %s' % type_name(value),) + args - raise e - else: - if class_ != value.class_: - raise ValueError(unwrap( - ''' - Error parsing %s - class should have been %s, but %s was - found - ''', - type_name(value), - CLASS_NUM_TO_NAME_MAP.get(value.class_), - CLASS_NUM_TO_NAME_MAP.get(class_, class_) - )) - if method != value.method: - # Allow parsing a primitive method as constructed if the value - # is indefinite length. This is to allow parsing BER. - ber_indef = method == 1 and value.method == 0 and trailer == b'\x00\x00' - if not ber_indef or not isinstance(value, Constructable): + if spec_params: + value = spec(contents=contents, **spec_params) + else: + value = spec(contents=contents) + + if spec is Any: + pass + + elif isinstance(value, Choice): + value.validate(class_, tag, contents) + try: + # Force parsing the Choice now + value.contents = header + value.contents + header = b'' + value.parse() + except (ValueError, TypeError) as e: + args = e.args[1:] + e.args = (e.args[0] + '\n while parsing %s' % type_name(value),) + args + raise e + + else: + if class_ != value.class_: + raise ValueError(unwrap( + ''' + Error parsing %s - class should have been %s, but %s was + found + ''', + type_name(value), + CLASS_NUM_TO_NAME_MAP.get(value.class_), + CLASS_NUM_TO_NAME_MAP.get(class_, class_) + )) + if method != value.method: + # Allow parsing a primitive method as constructed if the value + # is indefinite length. This is to allow parsing BER. + ber_indef = method == 1 and value.method == 0 and trailer == b'\x00\x00' + if not ber_indef or not isinstance(value, Constructable): + raise ValueError(unwrap( + ''' + Error parsing %s - method should have been %s, but %s was found + ''', + type_name(value), + METHOD_NUM_TO_NAME_MAP.get(value.method), + METHOD_NUM_TO_NAME_MAP.get(method, method) + )) + else: + value.method = method + value._indefinite = True + if tag != value.tag and tag != value._bad_tag: raise ValueError(unwrap( ''' - Error parsing %s - method should have been %s, but %s was found + Error parsing %s - tag should have been %s, but %s was found ''', type_name(value), - METHOD_NUM_TO_NAME_MAP.get(value.method), - METHOD_NUM_TO_NAME_MAP.get(method, method) + value.tag, + tag )) - else: - value.method = method - value._indefinite = True - if tag != value.tag and tag != value._bad_tag: - raise ValueError(unwrap( - ''' - Error parsing %s - tag should have been %s, but %s was found - ''', - type_name(value), - value.tag, - tag - )) # For explicitly tagged, un-speced parsings, we use a generic container # since we will be parsing the contents and discarding the outer object diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asn1crypto-0.23.0/asn1crypto/keys.py new/asn1crypto-0.24.0/asn1crypto/keys.py --- old/asn1crypto-0.23.0/asn1crypto/keys.py 2017-09-15 12:48:53.000000000 +0200 +++ new/asn1crypto-0.24.0/asn1crypto/keys.py 2017-11-22 17:15:11.000000000 +0100 @@ -30,7 +30,7 @@ ) from ._errors import unwrap from ._types import type_name, str_cls, byte_cls -from .algos import _ForceNullParameters, DigestAlgorithm, EncryptionAlgorithm +from .algos import _ForceNullParameters, DigestAlgorithm, EncryptionAlgorithm, RSAESOAEPParams from .core import ( Any, Asn1Value, @@ -930,6 +930,8 @@ _map = { # https://tools.ietf.org/html/rfc3279#page-19 '1.2.840.113549.1.1.1': 'rsa', + # https://tools.ietf.org/html/rfc3447#page-47 + '1.2.840.113549.1.1.7': 'rsaes_oaep', # https://tools.ietf.org/html/rfc3279#page-18 '1.2.840.10040.4.1': 'dsa', # https://tools.ietf.org/html/rfc3279#page-13 @@ -955,6 +957,7 @@ 'dsa': DSAParams, 'ec': ECDomainParameters, 'dh': DomainParameters, + 'rsaes_oaep': RSAESOAEPParams, } @@ -973,6 +976,7 @@ algorithm = self['algorithm']['algorithm'].native return { 'rsa': RSAPublicKey, + 'rsaes_oaep': RSAPublicKey, 'dsa': Integer, # We override the field spec with ECPoint so that users can easily # decompose the byte string into the constituent X and Y coords diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asn1crypto-0.23.0/asn1crypto/pem.py new/asn1crypto-0.24.0/asn1crypto/pem.py --- old/asn1crypto-0.23.0/asn1crypto/pem.py 2017-08-04 16:19:39.000000000 +0200 +++ new/asn1crypto-0.24.0/asn1crypto/pem.py 2017-11-28 17:18:08.000000000 +0100 @@ -16,7 +16,7 @@ import sys from ._errors import unwrap -from ._types import type_name, str_cls, byte_cls +from ._types import type_name as _type_name, str_cls, byte_cls if sys.version_info < (3,): from cStringIO import StringIO as BytesIO @@ -41,7 +41,7 @@ ''' byte_string must be a byte string, not %s ''', - type_name(byte_string) + _type_name(byte_string) )) return byte_string.find(b'-----BEGIN') != -1 or byte_string.find(b'---- BEGIN') != -1 @@ -51,15 +51,15 @@ """ Armors a DER-encoded byte string in PEM - :param der_bytes: - A byte string to be armored - :param type_name: A unicode string that will be capitalized and placed in the header and footer of the block. E.g. "CERTIFICATE", "PRIVATE KEY", etc. This will appear as "-----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----". + :param der_bytes: + A byte string to be armored + :param headers: An OrderedDict of the header lines to write after the BEGIN line @@ -71,7 +71,7 @@ raise TypeError(unwrap( ''' der_bytes must be a byte string, not %s - ''' % type_name(der_bytes) + ''' % _type_name(der_bytes) )) if not isinstance(type_name, str_cls): @@ -79,7 +79,7 @@ ''' type_name must be a unicode string, not %s ''', - type_name(type_name) + _type_name(type_name) )) type_name = type_name.upper().encode('ascii') @@ -132,7 +132,7 @@ ''' pem_bytes must be a byte string, not %s ''', - type_name(pem_bytes) + _type_name(pem_bytes) )) # Valid states include: "trash", "headers", "body" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asn1crypto-0.23.0/asn1crypto/version.py new/asn1crypto-0.24.0/asn1crypto/version.py --- old/asn1crypto-0.23.0/asn1crypto/version.py 2017-09-22 21:43:26.000000000 +0200 +++ new/asn1crypto-0.24.0/asn1crypto/version.py 2017-12-14 22:01:31.000000000 +0100 @@ -2,5 +2,5 @@ from __future__ import unicode_literals, division, absolute_import, print_function -__version__ = '0.23.0' -__version_info__ = (0, 23, 0) +__version__ = '0.24.0' +__version_info__ = (0, 24, 0) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asn1crypto-0.23.0/asn1crypto/x509.py new/asn1crypto-0.24.0/asn1crypto/x509.py --- old/asn1crypto-0.23.0/asn1crypto/x509.py 2017-09-22 21:43:26.000000000 +0200 +++ new/asn1crypto-0.24.0/asn1crypto/x509.py 2017-12-14 22:01:31.000000000 +0100 @@ -28,7 +28,7 @@ from ._iri import iri_to_uri, uri_to_iri from ._ordereddict import OrderedDict from ._types import type_name, str_cls, bytes_to_list -from .algos import AlgorithmIdentifier, SignedDigestAlgorithm +from .algos import AlgorithmIdentifier, AnyAlgorithmIdentifier, DigestAlgorithm, SignedDigestAlgorithm from .core import ( Any, BitString, @@ -36,6 +36,7 @@ Boolean, Choice, Concat, + Enumerated, GeneralizedTime, GeneralString, IA5String, @@ -517,6 +518,13 @@ '2.5.4.46': 'dn_qualifier', '2.5.4.65': 'pseudonym', '2.5.4.97': 'organization_identifier', + # https://www.trustedcomputinggroup.org/wp-content/uploads/Credential_Profile_EK_V2.0_R14_published.pdf + '2.23.133.2.1': 'tpm_manufacturer', + '2.23.133.2.2': 'tpm_model', + '2.23.133.2.3': 'tpm_version', + '2.23.133.2.4': 'platform_manufacturer', + '2.23.133.2.5': 'platform_model', + '2.23.133.2.6': 'platform_version', # https://tools.ietf.org/html/rfc2985#page-26 '1.2.840.113549.1.9.1': 'email_address', # Page 10 of https://cabforum.org/wp-content/uploads/EV-V1_5_5.pdf @@ -559,6 +567,12 @@ 'domain_component', 'name_distinguisher', 'organization_identifier', + 'tpm_manufacturer', + 'tpm_model', + 'tpm_version', + 'platform_manufacturer', + 'platform_model', + 'platform_version', ] @classmethod @@ -616,6 +630,12 @@ 'domain_component': 'Domain Component', 'name_distinguisher': 'Name Distinguisher', 'organization_identifier': 'Organization Identifier', + 'tpm_manufacturer': 'TPM Manufacturer', + 'tpm_model': 'TPM Model', + 'tpm_version': 'TPM Version', + 'platform_manufacturer': 'Platform Manufacturer', + 'platform_model': 'Platform Model', + 'platform_version': 'Platform Version', }.get(self.native, self.native) @@ -656,6 +676,12 @@ 'domain_component': DNSName, 'name_distinguisher': DirectoryString, 'organization_identifier': DirectoryString, + 'tpm_manufacturer': UTF8String, + 'tpm_model': UTF8String, + 'tpm_version': UTF8String, + 'platform_manufacturer': UTF8String, + 'platform_model': UTF8String, + 'platform_version': UTF8String, } _prepped = None @@ -1684,6 +1710,8 @@ '1.3.6.1.4.1.311.10.3.12': 'microsoft_document_signing', '1.3.6.1.4.1.311.10.3.13': 'microsoft_lifetime_signing', '1.3.6.1.4.1.311.10.3.14': 'microsoft_mobile_device_software', + # https://support.microsoft.com/en-us/help/287547/object-ids-associated-with-microsoft-cryptography + '1.3.6.1.4.1.311.20.2.2': 'microsoft_smart_card_logon', # https://opensource.apple.com/source # - /Security/Security-57031.40.6/Security/libsecurity_keychain/lib/SecPolicy.cpp # - /libsecurity_cssm/libsecurity_cssm-36064/lib/oidsalg.c @@ -1719,6 +1747,16 @@ '1.2.840.113625.100.1.32': 'apple_test_smp_encryption', '1.2.840.113635.100.1.33': 'apple_server_authentication', '1.2.840.113635.100.1.34': 'apple_pcs_escrow_service', + # http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.201-2.pdf + '2.16.840.1.101.3.6.8': 'piv_card_authentication', + '2.16.840.1.101.3.6.7': 'piv_content_signing', + # https://tools.ietf.org/html/rfc4556.html + '1.3.6.1.5.2.3.4': 'pkinit_kpclientauth', + '1.3.6.1.5.2.3.5': 'pkinit_kpkdc', + # https://www.adobe.com/devnet-docs/acrobatetk/tools/DigSig/changes.html + '1.2.840.113583.1.1.5': 'adobe_authentic_documents_trust', + # https://www.idmanagement.gov/wp-content/uploads/sites/1171/uploads/fpki-pivi-cert-profiles.pdf + '2.16.840.1.101.3.8.7': 'fpki_pivi_content_signing' } @@ -1775,6 +1813,232 @@ } +class Version(Integer): + _map = { + 0: 'v1', + 1: 'v2', + 2: 'v3', + } + + +class TPMSpecification(Sequence): + _fields = [ + ('family', UTF8String), + ('level', Integer), + ('revision', Integer), + ] + + +class SetOfTPMSpecification(SetOf): + _child_spec = TPMSpecification + + +class TCGSpecificationVersion(Sequence): + _fields = [ + ('major_version', Integer), + ('minor_version', Integer), + ('revision', Integer), + ] + + +class TCGPlatformSpecification(Sequence): + _fields = [ + ('version', TCGSpecificationVersion), + ('platform_class', OctetString), + ] + + +class SetOfTCGPlatformSpecification(SetOf): + _child_spec = TCGPlatformSpecification + + +class EKGenerationType(Enumerated): + _map = { + 0: 'internal', + 1: 'injected', + 2: 'internal_revocable', + 3: 'injected_revocable', + } + + +class EKGenerationLocation(Enumerated): + _map = { + 0: 'tpm_manufacturer', + 1: 'platform_manufacturer', + 2: 'ek_cert_signer', + } + + +class EKCertificateGenerationLocation(Enumerated): + _map = { + 0: 'tpm_manufacturer', + 1: 'platform_manufacturer', + 2: 'ek_cert_signer', + } + + +class EvaluationAssuranceLevel(Enumerated): + _map = { + 1: 'level1', + 2: 'level2', + 3: 'level3', + 4: 'level4', + 5: 'level5', + 6: 'level6', + 7: 'level7', + } + + +class EvaluationStatus(Enumerated): + _map = { + 0: 'designed_to_meet', + 1: 'evaluation_in_progress', + 2: 'evaluation_completed', + } + + +class StrengthOfFunction(Enumerated): + _map = { + 0: 'basic', + 1: 'medium', + 2: 'high', + } + + +class URIReference(Sequence): + _fields = [ + ('uniform_resource_identifier', IA5String), + ('hash_algorithm', DigestAlgorithm, {'optional': True}), + ('hash_value', BitString, {'optional': True}), + ] + + +class CommonCriteriaMeasures(Sequence): + _fields = [ + ('version', IA5String), + ('assurance_level', EvaluationAssuranceLevel), + ('evaluation_status', EvaluationStatus), + ('plus', Boolean, {'default': False}), + ('strengh_of_function', StrengthOfFunction, {'implicit': 0, 'optional': True}), + ('profile_oid', ObjectIdentifier, {'implicit': 1, 'optional': True}), + ('profile_url', URIReference, {'implicit': 2, 'optional': True}), + ('target_oid', ObjectIdentifier, {'implicit': 3, 'optional': True}), + ('target_uri', URIReference, {'implicit': 4, 'optional': True}), + ] + + +class SecurityLevel(Enumerated): + _map = { + 1: 'level1', + 2: 'level2', + 3: 'level3', + 4: 'level4', + } + + +class FIPSLevel(Sequence): + _fields = [ + ('version', IA5String), + ('level', SecurityLevel), + ('plus', Boolean, {'default': False}), + ] + + +class TPMSecurityAssertions(Sequence): + _fields = [ + ('version', Version, {'default': 'v1'}), + ('field_upgradable', Boolean, {'default': False}), + ('ek_generation_type', EKGenerationType, {'implicit': 0, 'optional': True}), + ('ek_generation_location', EKGenerationLocation, {'implicit': 1, 'optional': True}), + ('ek_certificate_generation_location', EKCertificateGenerationLocation, {'implicit': 2, 'optional': True}), + ('cc_info', CommonCriteriaMeasures, {'implicit': 3, 'optional': True}), + ('fips_level', FIPSLevel, {'implicit': 4, 'optional': True}), + ('iso_9000_certified', Boolean, {'implicit': 5, 'default': False}), + ('iso_9000_uri', IA5String, {'optional': True}), + ] + + +class SetOfTPMSecurityAssertions(SetOf): + _child_spec = TPMSecurityAssertions + + +class SubjectDirectoryAttributeId(ObjectIdentifier): + _map = { + # https://tools.ietf.org/html/rfc2256#page-11 + '2.5.4.52': 'supported_algorithms', + # https://www.trustedcomputinggroup.org/wp-content/uploads/Credential_Profile_EK_V2.0_R14_published.pdf + '2.23.133.2.16': 'tpm_specification', + '2.23.133.2.17': 'tcg_platform_specification', + '2.23.133.2.18': 'tpm_security_assertions', + # https://tools.ietf.org/html/rfc3739#page-18 + '1.3.6.1.5.5.7.9.1': 'pda_date_of_birth', + '1.3.6.1.5.5.7.9.2': 'pda_place_of_birth', + '1.3.6.1.5.5.7.9.3': 'pda_gender', + '1.3.6.1.5.5.7.9.4': 'pda_country_of_citizenship', + '1.3.6.1.5.5.7.9.5': 'pda_country_of_residence', + # https://holtstrom.com/michael/tools/asn1decoder.php + '1.2.840.113533.7.68.29': 'entrust_user_role', + } + + +class SetOfGeneralizedTime(SetOf): + _child_spec = GeneralizedTime + + +class SetOfDirectoryString(SetOf): + _child_spec = DirectoryString + + +class SetOfPrintableString(SetOf): + _child_spec = PrintableString + + +class SupportedAlgorithm(Sequence): + _fields = [ + ('algorithm_identifier', AnyAlgorithmIdentifier), + ('intended_usage', KeyUsage, {'explicit': 0, 'optional': True}), + ('intended_certificate_policies', CertificatePolicies, {'explicit': 1, 'optional': True}), + ] + + +class SetOfSupportedAlgorithm(SetOf): + _child_spec = SupportedAlgorithm + + +class SubjectDirectoryAttribute(Sequence): + _fields = [ + ('type', SubjectDirectoryAttributeId), + ('values', Any), + ] + + _oid_pair = ('type', 'values') + _oid_specs = { + 'supported_algorithms': SetOfSupportedAlgorithm, + 'tpm_specification': SetOfTPMSpecification, + 'tcg_platform_specification': SetOfTCGPlatformSpecification, + 'tpm_security_assertions': SetOfTPMSecurityAssertions, + 'pda_date_of_birth': SetOfGeneralizedTime, + 'pda_place_of_birth': SetOfDirectoryString, + 'pda_gender': SetOfPrintableString, + 'pda_country_of_citizenship': SetOfPrintableString, + 'pda_country_of_residence': SetOfPrintableString, + } + + def _values_spec(self): + type_ = self['type'].native + if type_ in self._oid_specs: + return self._oid_specs[type_] + return SetOf + + _spec_callbacks = { + 'values': _values_spec + } + + +class SubjectDirectoryAttributes(SequenceOf): + _child_spec = SubjectDirectoryAttribute + + class ExtensionId(ObjectIdentifier): _map = { '2.5.29.9': 'subject_directory_attributes', @@ -1814,7 +2078,7 @@ _oid_pair = ('extn_id', 'extn_value') _oid_specs = { - 'subject_directory_attributes': Attributes, + 'subject_directory_attributes': SubjectDirectoryAttributes, 'key_identifier': OctetString, 'key_usage': KeyUsage, 'private_key_usage_period': PrivateKeyUsagePeriod, @@ -1844,14 +2108,6 @@ _child_spec = Extension -class Version(Integer): - _map = { - 0: 'v1', - 1: 'v2', - 2: 'v3', - } - - class TbsCertificate(Sequence): _fields = [ ('version', Version, {'explicit': 0, 'default': 'v1'}), @@ -1893,6 +2149,7 @@ _extended_key_usage_value = None _authority_information_access_value = None _subject_information_access_value = None + _private_key_usage_period_value = None _tls_feature_value = None _ocsp_no_check_value = None _issuer_serial = None @@ -1939,18 +2196,32 @@ return self._critical_extensions @property + def private_key_usage_period_value(self): + """ + This extension is used to constrain the period over which the subject + private key may be used + + :return: + None or a PrivateKeyUsagePeriod object + """ + + if not self._processed_extensions: + self._set_extensions() + return self._private_key_usage_period_value + + @property def subject_directory_attributes_value(self): """ This extension is used to contain additional identification attributes about the subject. :return: - None or an Attributes object + None or a SubjectDirectoryAttributes object """ if not self._processed_extensions: self._set_extensions() - return self._key_identifier_value + return self._subject_directory_attributes @property def key_identifier_value(self): @@ -2503,11 +2774,14 @@ def self_signed(self): """ :return: - A unicode string of "yes", "no" or "maybe". The "maybe" result will - be returned if the certificate does not contain a key identifier - extension, but is issued by the subject. In this case the - certificate signature will need to be verified using the subject - public key to determine a "yes" or "no" answer. + A unicode string of "no" or "maybe". The "maybe" result will + be returned if the certificate issuer and subject are the same. + If a key identifier and authority key identifier are present, + they will need to match otherwise "no" will be returned. + + To verify is a certificate is truly self-signed, the signature + will need to be verified. See the certvalidator package for + one possible solution. """ if self._self_signed is None: @@ -2515,9 +2789,9 @@ if self.self_issued: if self.key_identifier: if not self.authority_key_identifier: - self._self_signed = 'yes' + self._self_signed = 'maybe' elif self.authority_key_identifier == self.key_identifier: - self._self_signed = 'yes' + self._self_signed = 'maybe' else: self._self_signed = 'maybe' return self._self_signed diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asn1crypto-0.23.0/asn1crypto.egg-info/PKG-INFO new/asn1crypto-0.24.0/asn1crypto.egg-info/PKG-INFO --- old/asn1crypto-0.23.0/asn1crypto.egg-info/PKG-INFO 2017-09-22 22:36:35.000000000 +0200 +++ new/asn1crypto-0.24.0/asn1crypto.egg-info/PKG-INFO 2017-12-14 22:04:10.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: asn1crypto -Version: 0.23.0 +Version: 0.24.0 Summary: Fast ASN.1 parser and serializer with definitions for private keys, public keys, certificates, CRL, OCSP, CMS, PKCS#3, PKCS#7, PKCS#8, PKCS#12, PKCS#5, X.509 and TSP Home-page: https://github.com/wbond/asn1crypto Author: wbond diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asn1crypto-0.23.0/changelog.md new/asn1crypto-0.24.0/changelog.md --- old/asn1crypto-0.23.0/changelog.md 2017-09-22 21:43:26.000000000 +0200 +++ new/asn1crypto-0.24.0/changelog.md 2017-12-14 22:01:31.000000000 +0100 @@ -1,5 +1,24 @@ # changelog +## 0.24.0 + + - `x509.Certificate().self_signed` will no longer return `"yes"` under any + circumstances. This helps prevent confusion since the library does not + verify the signature. Instead a library like oscrypto should be used + to confirm if a certificate is self-signed. + - Added various OIDs to `x509.KeyPurposeId()` + - Added `x509.Certificate().private_key_usage_period_value` + - Added structures for parsing common subject directory attributes for + X.509 certificates, including `x509.SubjectDirectoryAttribute()` + - Added `algos.AnyAlgorithmIdentifier()` for situations where an + algorithm identifier may contain a digest, signed digest or encryption + algorithm OID + - Fixed a bug with `x509.Certificate().subject_directory_attributes_value` + not returning the correct value + - Fixed a bug where explicitly-tagged fields in a `core.Sequence()` would + not function properly when the field had a default value + - Fixed a bug with type checking in `pem.armor()` + ## 0.23.0 - Backwards compatibility break: the `tag_type`, `explicit_tag` and diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asn1crypto-0.23.0/readme.md new/asn1crypto-0.24.0/readme.md --- old/asn1crypto-0.23.0/readme.md 2017-09-22 21:43:26.000000000 +0200 +++ new/asn1crypto-0.24.0/readme.md 2017-12-14 22:01:31.000000000 +0100 @@ -110,7 +110,7 @@ ## Current Release -0.23.0 - [changelog](changelog.md) +0.24.0 - [changelog](changelog.md) ## Dependencies
