diff --git a/README.rst b/README.rst index d800c14f..7b3bc9b1 100644 --- a/README.rst +++ b/README.rst @@ -56,8 +56,6 @@ Requirements - `Cryptography `_ -- `pyasn1 `_ - - `six `_ License diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 6454614e..2d3afce9 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -4,6 +4,37 @@ Changelog ********* +v0.7.0 +====== + +(not yet released) + +Dependency changes +------------------ + +pyasn1 is no longer needed + +Now depends transitively (via the cryptography module) on OpenSSL +1.1.1 or later for Brainpool, X25519, Ed25519. + +API additions +------------- + +PGPSignatures represents a detached signature, which can contain more +than a single signature. It is a simple sequence of individual +PGPSignature objects. + +API changes +----------- + +Armorable.is_ascii() is deprecated. You probably want +Armorable.is_utf8() instead, since OpenPGP assumes that all text is +UTF-8. + + +EllipticCurveOID.Invalid was removed -- EllipticCurveOID only +enumerates supported curves now. + v0.6.0 ====== diff --git a/pgpy/__init__.py b/pgpy/__init__.py index b4c30d13..472cf75f 100644 --- a/pgpy/__init__.py +++ b/pgpy/__init__.py @@ -5,6 +5,7 @@ from .pgp import PGPKeyring from .pgp import PGPMessage from .pgp import PGPSignature +from .pgp import PGPSignatures from .pgp import PGPUID __all__ = ['constants', @@ -13,4 +14,5 @@ 'PGPKeyring', 'PGPMessage', 'PGPSignature', + 'PGPSignatures', 'PGPUID', ] diff --git a/pgpy/_curves.py b/pgpy/_curves.py deleted file mode 100644 index 14f25284..00000000 --- a/pgpy/_curves.py +++ /dev/null @@ -1,103 +0,0 @@ -""" _curves.py -specify some additional curves that OpenSSL provides but cryptography doesn't explicitly expose -""" - -from cryptography import utils - -from cryptography.hazmat.primitives.asymmetric import ec - -from cryptography.hazmat.bindings.openssl.binding import Binding - -__all__ = tuple() - -# TODO: investigate defining additional curves using EC_GROUP_new_curve -# https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography#Defining_Curves - - -def _openssl_get_supported_curves(): - if hasattr(_openssl_get_supported_curves, '_curves'): - return _openssl_get_supported_curves._curves - - # use cryptography's cffi bindings to get an array of curve names - b = Binding() - cn = b.lib.EC_get_builtin_curves(b.ffi.NULL, 0) - cs = b.ffi.new('EC_builtin_curve[]', cn) - b.lib.EC_get_builtin_curves(cs, cn) - - # store the result so we don't have to do all of this every time - curves = { b.ffi.string(b.lib.OBJ_nid2sn(c.nid)).decode('utf-8') for c in cs } - # Ed25519 and X25519 are always present in cryptography>=2.6 - # The python cryptography lib provides a different interface for these curves, - # so they are handled differently in the ECDHPriv/Pub and EdDSAPriv/Pub classes - curves |= {'X25519', 'ed25519'} - _openssl_get_supported_curves._curves = curves - return curves - - -def use_legacy_cryptography_decorator(): - """ - The decorator utils.register_interface was removed in version 38.0.0. Keep using it - if the decorator exists, inherit from `ec.EllipticCurve` otherwise. - """ - return hasattr(utils, "register_interface") and callable(utils.register_interface) - - -if use_legacy_cryptography_decorator(): - @utils.register_interface(ec.EllipticCurve) - class BrainpoolP256R1(object): - name = 'brainpoolP256r1' - key_size = 256 - - - @utils.register_interface(ec.EllipticCurve) # noqa: E303 - class BrainpoolP384R1(object): - name = 'brainpoolP384r1' - key_size = 384 - - - @utils.register_interface(ec.EllipticCurve) # noqa: E303 - class BrainpoolP512R1(object): - name = 'brainpoolP512r1' - key_size = 512 - - - @utils.register_interface(ec.EllipticCurve) # noqa: E303 - class X25519(object): - name = 'X25519' - key_size = 256 - - - @utils.register_interface(ec.EllipticCurve) # noqa: E303 - class Ed25519(object): - name = 'ed25519' - key_size = 256 -else: - class BrainpoolP256R1(ec.EllipticCurve): - name = 'brainpoolP256r1' - key_size = 256 - - - class BrainpoolP384R1(ec.EllipticCurve): # noqa: E303 - name = 'brainpoolP384r1' - key_size = 384 - - - class BrainpoolP512R1(ec.EllipticCurve): # noqa: E303 - name = 'brainpoolP512r1' - key_size = 512 - - - class X25519(ec.EllipticCurve): # noqa: E303 - name = 'X25519' - key_size = 256 - - - class Ed25519(ec.EllipticCurve): # noqa: E303 - name = 'ed25519' - key_size = 256 - - -# add these curves to the _CURVE_TYPES list -for curve in [BrainpoolP256R1, BrainpoolP384R1, BrainpoolP512R1, X25519, Ed25519]: - if curve.name not in ec._CURVE_TYPES and curve.name in _openssl_get_supported_curves(): - ec._CURVE_TYPES[curve.name] = curve diff --git a/pgpy/constants.py b/pgpy/constants.py index 28a4561a..933c100b 100644 --- a/pgpy/constants.py +++ b/pgpy/constants.py @@ -12,18 +12,18 @@ from enum import IntEnum from enum import IntFlag -from pyasn1.type.univ import ObjectIdentifier +from typing import NamedTuple, Optional, Type, Union from cryptography.hazmat.backends import openssl -from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.hazmat.primitives.asymmetric import ec, x25519, ed25519 from cryptography.hazmat.primitives.ciphers import algorithms from .types import FlagEnum from .decorators import classproperty -from ._curves import BrainpoolP256R1, BrainpoolP384R1, BrainpoolP512R1, X25519, Ed25519 __all__ = [ 'Backend', + 'ECFields', 'EllipticCurveOID', 'ECPointFormat', 'PacketTag', @@ -55,83 +55,6 @@ class Backend(Enum): OpenSSL = openssl.backend -class EllipticCurveOID(Enum): - """OIDs for supported elliptic curves.""" - # these are specified as: - # id = (oid, curve) - Invalid = ('', ) - #: DJB's fast elliptic curve - Curve25519 = ('1.3.6.1.4.1.3029.1.5.1', X25519) - #: Twisted Edwards variant of Curve25519 - Ed25519 = ('1.3.6.1.4.1.11591.15.1', Ed25519) - #: NIST P-256, also known as SECG curve secp256r1 - NIST_P256 = ('1.2.840.10045.3.1.7', ec.SECP256R1) - #: NIST P-384, also known as SECG curve secp384r1 - NIST_P384 = ('1.3.132.0.34', ec.SECP384R1) - #: NIST P-521, also known as SECG curve secp521r1 - NIST_P521 = ('1.3.132.0.35', ec.SECP521R1) - #: Brainpool Standard Curve, 256-bit - #: - #: .. note:: - #: Requires OpenSSL >= 1.0.2 - Brainpool_P256 = ('1.3.36.3.3.2.8.1.1.7', BrainpoolP256R1) - #: Brainpool Standard Curve, 384-bit - #: - #: .. note:: - #: Requires OpenSSL >= 1.0.2 - Brainpool_P384 = ('1.3.36.3.3.2.8.1.1.11', BrainpoolP384R1) - #: Brainpool Standard Curve, 512-bit - #: - #: .. note:: - #: Requires OpenSSL >= 1.0.2 - Brainpool_P512 = ('1.3.36.3.3.2.8.1.1.13', BrainpoolP512R1) - #: SECG curve secp256k1 - SECP256K1 = ('1.3.132.0.10', ec.SECP256K1) - - def __new__(cls, oid, curve=None): - # preprocessing stage for enum members: - # - set enum_member.value to ObjectIdentifier(oid) - # - if curve is not None and curve.name is in ec._CURVE_TYPES, set enum_member.curve to curve - # - otherwise, set enum_member.curve to None - obj = object.__new__(cls) - obj._value_ = ObjectIdentifier(oid) - obj.curve = None - - if curve is not None and curve.name in ec._CURVE_TYPES: - obj.curve = curve - - return obj - - @property - def can_gen(self): - return self.curve is not None - - @property - def key_size(self): - if self.curve is not None: - return self.curve.key_size - - @property - def kdf_halg(self): - # return the hash algorithm to specify in the KDF fields when generating a key - algs = {256: HashAlgorithm.SHA256, - 384: HashAlgorithm.SHA384, - 512: HashAlgorithm.SHA512, - 521: HashAlgorithm.SHA512} - - return algs.get(self.key_size, None) - - @property - def kek_alg(self): - # return the AES algorithm to specify in the KDF fields when generating a key - algs = {256: SymmetricKeyAlgorithm.AES128, - 384: SymmetricKeyAlgorithm.AES192, - 512: SymmetricKeyAlgorithm.AES256, - 521: SymmetricKeyAlgorithm.AES256} - - return algs.get(self.key_size, None) - - class ECPointFormat(IntEnum): # https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-07#appendix-B Standard = 0x04 @@ -247,6 +170,7 @@ def gen_key(self): class PubKeyAlgorithm(IntEnum): """Supported public key algorithms.""" + Unknown = -1 Invalid = 0x00 #: Signifies that a key is an RSA key. RSAEncryptOrSign = 0x01 @@ -264,6 +188,12 @@ class PubKeyAlgorithm(IntEnum): DiffieHellman = 0x15 # X9.42 EdDSA = 0x16 # https://tools.ietf.org/html/draft-koch-eddsa-for-openpgp-04 + @classmethod + def _missing_(cls, val: object) -> 'PubKeyAlgorithm': + if not isinstance(val, int): + raise TypeError(f"cannot look up PubKeyAlgorithm by non-int {type(val)}") + return cls.Unknown + @property def can_gen(self): return self in {PubKeyAlgorithm.RSAEncryptOrSign, @@ -351,6 +281,7 @@ def decompress(self, data): class HashAlgorithm(IntEnum): """Supported hash algorithms.""" + Unknown = -1 Invalid = 0x00 MD5 = 0x01 SHA1 = 0x02 @@ -367,6 +298,12 @@ class HashAlgorithm(IntEnum): #SHA3_384 = 14 #SHA3_512 = 15 + @classmethod + def _missing_(cls, val: object) -> 'HashAlgorithm': + if not isinstance(val, int): + raise TypeError(f"cannot look up HashAlgorithm by non-int {type(val)}") + return cls.Unknown + def __init__(self, *args): super(self.__class__, self).__init__() self._tuned_count = 255 @@ -409,6 +346,135 @@ def is_considered_secure(self): return issues +class ECFields(NamedTuple): + name: str + OID: str + OID_der: bytes + key_size: int # in bits + kdf_halg: HashAlgorithm + kek_alg: SymmetricKeyAlgorithm + curve: Type + + def __repr__(self) -> str: + return f'' + + +class EllipticCurveOID(Enum): + """Supported elliptic curves.""" + + #: DJB's fast elliptic curve + Curve25519 = (x25519, '1.3.6.1.4.1.3029.1.5.1', + b'\x2b\x06\x01\x04\x01\x97\x55\x01\x05\x01', + 'X25519', 256) + #: Twisted Edwards variant of Curve25519 + Ed25519 = (ed25519, '1.3.6.1.4.1.11591.15.1', + b'\x2b\x06\x01\x04\x01\xda\x47\x0f\x01', + 'Ed25519', 256) + #: NIST P-256, also known as SECG curve secp256r1 + NIST_P256 = (ec.SECP256R1, '1.2.840.10045.3.1.7', + b'\x2a\x86\x48\xce\x3d\x03\x01\x07') + #: NIST P-384, also known as SECG curve secp384r1 + NIST_P384 = (ec.SECP384R1, '1.3.132.0.34', + b'\x2b\x81\x04\x00\x22') + #: NIST P-521, also known as SECG curve secp521r1 + NIST_P521 = (ec.SECP521R1, '1.3.132.0.35', + b'\x2b\x81\x04\x00\x23') + #: Brainpool Standard Curve, 256-bit + Brainpool_P256 = (ec.BrainpoolP256R1, '1.3.36.3.3.2.8.1.1.7', + b'\x2b\x24\x03\x03\x02\x08\x01\x01\x07') + #: Brainpool Standard Curve, 384-bit + Brainpool_P384 = (ec.BrainpoolP384R1, '1.3.36.3.3.2.8.1.1.11', + b'\x2b\x24\x03\x03\x02\x08\x01\x01\x0b') + #: Brainpool Standard Curve, 512-bit + Brainpool_P512 = (ec.BrainpoolP512R1, '1.3.36.3.3.2.8.1.1.13', + b'\x2b\x24\x03\x03\x02\x08\x01\x01\x0d') + #: SECG curve secp256k1 + SECP256K1 = (ec.SECP256K1, '1.3.132.0.10', + b'\x2b\x81\x04\x00\x0a') + + def __new__(cls, impl_cls: Type, oid: str, oid_der: bytes, name: Optional[str] = None, key_size_bits: Optional[int] = None) -> "EllipticCurveOID": + # preprocessing stage for enum members: + # - set enum_member.value to ObjectIdentifier(oid) + # - if curve is not None and curve.name is in ec._CURVE_TYPES, set enum_member.curve to curve + # - otherwise, set enum_member.curve to None + obj = object.__new__(cls) + if name is None: + newname = impl_cls.name + if not isinstance(newname, str): + raise TypeError(f"{impl_cls}.name is not string!") + name = newname + if key_size_bits is None: + newks = impl_cls.key_size + if not isinstance(newks, int): + raise TypeError(f"{impl_cls}.name is not string!") + key_size_bits = newks + + algs = {256: (HashAlgorithm.SHA256, SymmetricKeyAlgorithm.AES128), + 384: (HashAlgorithm.SHA384, SymmetricKeyAlgorithm.AES192), + 512: (HashAlgorithm.SHA512, SymmetricKeyAlgorithm.AES256), + 521: (HashAlgorithm.SHA512, SymmetricKeyAlgorithm.AES256)} + + (kdf_alg, kek_alg) = algs[key_size_bits] + + obj._value_ = ECFields(name, oid, oid_der, key_size_bits, kdf_alg, kek_alg, impl_cls) + + return obj + + @classmethod + def from_key_size(cls, key_size: int) -> Optional["EllipticCurveOID"]: + for c in EllipticCurveOID: + if c.value.key_size == key_size: + return c + warnings.warn(f"Cannot find any Elliptic curve of size: {key_size}") + return None + + @classmethod + def from_OID(cls, oid: bytes) -> Union["EllipticCurveOID", bytes]: + for c in EllipticCurveOID: + if c.value.OID_der == oid: + return c + warnings.warn(f"Unknown Elliptic curve OID: {oid!r}") + return oid + + @classmethod + def parse(cls, packet: bytearray) -> Union["EllipticCurveOID", bytes]: + oidlen = packet[0] + del packet[0] + ret = EllipticCurveOID.from_OID(bytes(packet[:oidlen])) + del packet[:oidlen] + return ret + + @property + def key_size(self) -> int: + return self.value.key_size + + @property + def oid(self) -> str: + return self.value.OID + + @property + def kdf_halg(self) -> HashAlgorithm: + return self.value.kdf_halg + + @property + def kek_alg(self) -> SymmetricKeyAlgorithm: + return self.value.kek_alg + + @property + def curve(self) -> Type: + return self.value.curve + + @property + def can_gen(self) -> bool: + return True + + def __bytes__(self) -> bytes: + return bytes([len(self.value.OID_der)]) + self.value.OID_der + + def __len__(self) -> int: + return len(self.value.OID_der) + 1 + + class RevocationReason(IntEnum): """Reasons explaining why a key or certificate was revoked.""" #: No reason was specified. This is the default reason. @@ -521,12 +587,19 @@ class KeyServerPreferences(FlagEnum): class String2KeyType(IntEnum): + Unknown = -1 Simple = 0 Salted = 1 Reserved = 2 Iterated = 3 GNUExtension = 101 + @classmethod + def _missing_(cls, val: object) -> 'String2KeyType': + if not isinstance(val, int): + raise TypeError(f"cannot look up String2KeyType by non-int {type(val)}") + return cls.Unknown + class S2KGNUExtension(IntEnum): NoSecret = 1 diff --git a/pgpy/packet/fields.py b/pgpy/packet/fields.py index c94021c6..70d44b98 100644 --- a/pgpy/packet/fields.py +++ b/pgpy/packet/fields.py @@ -16,11 +16,7 @@ except ImportError: collections_abc = collections -from pyasn1.codec.der import decoder -from pyasn1.codec.der import encoder -from pyasn1.type.univ import Integer -from pyasn1.type.univ import Sequence -from pyasn1.type.namedtype import NamedTypes, NamedType +from typing import Union from cryptography.exceptions import InvalidSignature @@ -35,6 +31,7 @@ from cryptography.hazmat.primitives.asymmetric import ed25519 from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives.asymmetric import x25519 +from cryptography.hazmat.primitives.asymmetric import utils from cryptography.hazmat.primitives.kdf.concatkdf import ConcatKDFHash @@ -69,6 +66,7 @@ from ..symenc import _encrypt from ..types import Field +from ..types import Fingerprint __all__ = ['SubPackets', 'UserAttributeSubPackets', @@ -299,65 +297,23 @@ def from_signer(self, sig): class DSASignature(Signature): __mpis__ = ('r', 's') - def __sig__(self): - # return the signature data into an ASN.1 sequence of integers in DER format - seq = Sequence(componentType=NamedTypes(*[NamedType(n, Integer()) for n in self.__mpis__])) - for n in self.__mpis__: - seq.setComponentByName(n, getattr(self, n)) - - return encoder.encode(seq) - - def from_signer(self, sig): - ##TODO: just use pyasn1 for this - def _der_intf(_asn): - if _asn[0] != 0x02: # pragma: no cover - raise ValueError("Expected: Integer (0x02). Got: 0x{:02X}".format(_asn[0])) - del _asn[0] - - if _asn[0] & 0x80: # pragma: no cover - llen = _asn[0] & 0x7F - del _asn[0] - - flen = self.bytes_to_int(_asn[:llen]) - del _asn[:llen] - - else: - flen = _asn[0] & 0x7F - del _asn[0] - - i = self.bytes_to_int(_asn[:flen]) - del _asn[:flen] - return i - - if isinstance(sig, bytes): - sig = bytearray(sig) - - # this is a very limited asn1 decoder - it is only intended to decode a DER encoded sequence of integers - if not sig[0] == 0x30: - raise NotImplementedError("Expected: Sequence (0x30). Got: 0x{:02X}".format(sig[0])) - del sig[0] + def __sig__(self) -> bytes: + # return the RFC 3279 encoding: + return utils.encode_dss_signature(self.r, self.s) - # skip the sequence length field - if sig[0] & 0x80: # pragma: no cover - llen = sig[0] & 0x7F - del sig[:llen + 1] + def from_signer(self, sig: bytes) -> None: + # set up from the RFC 3279 encoding: + (r, s) = utils.decode_dss_signature(sig) + self.r = MPI(r) + self.s = MPI(s) - else: - del sig[0] - - self.r = MPI(_der_intf(sig)) - self.s = MPI(_der_intf(sig)) - - def parse(self, packet): + def parse(self, packet: bytearray) -> None: self.r = MPI(packet) self.s = MPI(packet) class ECDSASignature(DSASignature): - def from_signer(self, sig): - seq, _ = decoder.decode(sig) - self.r = MPI(seq[0]) - self.s = MPI(seq[1]) + pass class EdDSASignature(DSASignature): @@ -557,14 +513,14 @@ def __init__(self): self.oid = None def __len__(self): - return len(self.p) + len(encoder.encode(self.oid.value)) - 1 + return len(self.p) + len(self.oid) def __pubkey__(self): return ec.EllipticCurvePublicNumbers(self.p.x, self.p.y, self.oid.curve()).public_key(default_backend()) def __bytearray__(self): _b = bytearray() - _b += encoder.encode(self.oid.value)[1:] + _b += bytes(self.oid) _b += self.p.to_mpibytes() return _b @@ -581,18 +537,14 @@ def verify(self, subj, sigbytes, hash_alg): return True def parse(self, packet): - oidlen = packet[0] - del packet[0] - _oid = bytearray(b'\x06') - _oid.append(oidlen) - _oid += bytearray(packet[:oidlen]) - oid, _ = decoder.decode(bytes(_oid)) - self.oid = EllipticCurveOID(oid) - del packet[:oidlen] + self.oid = EllipticCurveOID.parse(packet) - self.p = ECPoint(packet) - if self.p.format != ECPointFormat.Standard: - raise PGPIncompatibleECPointFormatError("Only Standard format is valid for ECDSA") + if isinstance(self.oid, EllipticCurveOID): + self.p = ECPoint(packet) + if self.p.format != ECPointFormat.Standard: + raise PGPIncompatibleECPointFormatError("Only Standard format is valid for ECDSA") + else: + self.p = MPI(packet) class EdDSAPub(PubKey): @@ -603,11 +555,11 @@ def __init__(self): self.oid = None def __len__(self): - return len(self.p) + len(encoder.encode(self.oid.value)) - 1 + return len(self.p) + len(self.oid) def __bytearray__(self): _b = bytearray() - _b += encoder.encode(self.oid.value)[1:] + _b += bytes(self.oid) _b += self.p.to_mpibytes() return _b @@ -632,18 +584,14 @@ def verify(self, subj, sigbytes, hash_alg): return True def parse(self, packet): - oidlen = packet[0] - del packet[0] - _oid = bytearray(b'\x06') - _oid.append(oidlen) - _oid += bytearray(packet[:oidlen]) - oid, _ = decoder.decode(bytes(_oid)) - self.oid = EllipticCurveOID(oid) - del packet[:oidlen] + self.oid = EllipticCurveOID.parse(packet) - self.p = ECPoint(packet) - if self.p.format != ECPointFormat.Native: - raise PGPIncompatibleECPointFormatError("Only Native format is valid for EdDSA") + if isinstance(self.oid, EllipticCurveOID): + self.p = ECPoint(packet) + if self.p.format != ECPointFormat.Native: + raise PGPIncompatibleECPointFormatError("Only Native format is valid for EdDSA") + else: + self.p = MPI(packet) class ECDHPub(PubKey): @@ -655,7 +603,7 @@ def __init__(self): self.kdf = ECKDF() def __len__(self): - return len(self.p) + len(self.kdf) + len(encoder.encode(self.oid.value)) - 1 + return len(self.p) + len(self.kdf) + len(self.oid) def __pubkey__(self): if self.oid == EllipticCurveOID.Curve25519: @@ -663,9 +611,9 @@ def __pubkey__(self): else: return ec.EllipticCurvePublicNumbers(self.p.x, self.p.y, self.oid.curve()).public_key(default_backend()) - def __bytearray__(self): + def __bytearray__(self) -> bytearray: _b = bytearray() - _b += encoder.encode(self.oid.value)[1:] + _b += bytes(self.oid) _b += self.p.to_mpibytes() _b += self.kdf.__bytearray__() return _b @@ -705,22 +653,18 @@ def parse(self, packet): used to wrap the symmetric key used for the message encryption; see Section 8 for details """ - oidlen = packet[0] - del packet[0] - _oid = bytearray(b'\x06') - _oid.append(oidlen) - _oid += bytearray(packet[:oidlen]) - oid, _ = decoder.decode(bytes(_oid)) - - self.oid = EllipticCurveOID(oid) - del packet[:oidlen] + self.oid = EllipticCurveOID.parse(packet) + + if isinstance(self.oid, EllipticCurveOID): + self.p = ECPoint(packet) + if self.oid == EllipticCurveOID.Curve25519: + if self.p.format != ECPointFormat.Native: + raise PGPIncompatibleECPointFormatError("Only Native format is valid for Curve25519") + elif self.p.format != ECPointFormat.Standard: + raise PGPIncompatibleECPointFormatError("Only Standard format is valid for this curve") + else: + self.p = MPI(packet) - self.p = ECPoint(packet) - if self.oid == EllipticCurveOID.Curve25519: - if self.p.format != ECPointFormat.Native: - raise PGPIncompatibleECPointFormatError("Only Native format is valid for Curve25519") - elif self.p.format != ECPointFormat.Standard: - raise PGPIncompatibleECPointFormatError("Only Standard format is valid for this curve") self.kdf.parse(packet) @@ -839,13 +783,17 @@ def encalg_int(self, val): self._encalg = SymmetricKeyAlgorithm(val) @sdproperty - def specifier(self): + def specifier(self) -> String2KeyType: return self._specifier - @specifier.register(int) - @specifier.register(String2KeyType) - def specifier_int(self, val): - self._specifier = String2KeyType(val) + @specifier.register + def specifier_int(self, val: int) -> None: + if isinstance(val, String2KeyType): + self._specifier = val + else: + self._specifier = String2KeyType(val) + if self._specifier is String2KeyType.Unknown: + self._opaque_specifier: int = val @sdproperty def gnuext(self): @@ -903,7 +851,10 @@ def __bytearray__(self): _bytes.append(self.usage) if bool(self): _bytes.append(self.encalg) - _bytes.append(self.specifier) + if self.specifier is String2KeyType.Unknown: + _bytes.append(self._opaque_specifier) + else: + _bytes.append(self.specifier) if self.specifier == String2KeyType.GNUExtension: return self._experimental_bytearray(_bytes) if self.specifier >= String2KeyType.Simple: @@ -938,7 +889,10 @@ def __copy__(self): s2k = String2Key() s2k.usage = self.usage s2k.encalg = self.encalg - s2k.specifier = self.specifier + if bool(self) and self.specifier is String2KeyType.Unknown: + s2k.specifier = self._opaque_specifier + else: + s2k.specifier = self.specifier s2k.gnuext = self.gnuext s2k.iv = self.iv s2k.halg = self.halg @@ -1121,12 +1075,12 @@ def parse(self, packet): self.encalg = packet[0] del packet[0] - def derive_key(self, s, curve, pkalg, fingerprint): + def derive_key(self, s: bytes, curve: EllipticCurveOID, pkalg: PubKeyAlgorithm, fingerprint: Fingerprint) -> bytes: # wrapper around the Concatenation KDF method provided by cryptography # assemble the additional data as defined in RFC 6637: # Param = curve_OID_len || curve_OID || public_key_alg_ID || 03 || 01 || KDF_hash_ID || KEK_alg_ID for AESKeyWrap || "Anonymous data = bytearray() - data += encoder.encode(curve.value)[1:] + data += bytes(curve) data.append(pkalg) data += b'\x03\x01' data.append(self.halg) @@ -1474,14 +1428,17 @@ def _compute_chksum(self): chs = sum(bytearray(self.s.to_mpibytes())) % 65536 self.chksum = bytearray(self.int_to_bytes(chs, 2)) - def _generate(self, oid): + def _generate(self, params: Union[int, EllipticCurveOID]) -> None: if any(c != 0 for c in self): # pragma: no cover raise PGPError("Key is already populated!") - self.oid = EllipticCurveOID(oid) - - if not self.oid.can_gen: - raise ValueError("Curve not currently supported: {}".format(oid.name)) + if isinstance(params, int): + oid = EllipticCurveOID.from_key_size(params) + if oid is None: + raise ValueError("No supported Elliptic Curve of size {params}") + self.oid = oid + else: + self.oid = params pk = ec.generate_private_key(self.oid.curve(), default_backend()) pubn = pk.public_key().public_numbers() @@ -1523,14 +1480,20 @@ def _compute_chksum(self): chs = sum(bytearray(self.s.to_mpibytes())) % 65536 self.chksum = bytearray(self.int_to_bytes(chs, 2)) - def _generate(self, oid): + def _generate(self, params: Union[int, EllipticCurveOID]) -> None: if any(c != 0 for c in self): # pragma: no cover raise PGPError("Key is already populated!") - self.oid = EllipticCurveOID(oid) + if isinstance(params, int): + oid = EllipticCurveOID.from_key_size(params) + if oid is None: + raise ValueError("No supported Elliptic Curve of size {params}") + self.oid = oid + else: + self.oid = params if self.oid != EllipticCurveOID.Ed25519: - raise ValueError("EdDSA only supported with {}".format(EllipticCurveOID.Ed25519)) + raise ValueError(f"EdDSA only supported with {EllipticCurveOID.Ed25519}, not {self.oid}") pk = ed25519.Ed25519PrivateKey.generate() x = pk.public_key().public_bytes(encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw) @@ -1597,8 +1560,14 @@ def __privkey__(self): else: return ECDSAPriv.__privkey__(self) - def _generate(self, oid): - _oid = EllipticCurveOID(oid) + def _generate(self, params: Union[int, EllipticCurveOID]) -> None: + if isinstance(params, int): + _oid = EllipticCurveOID.from_key_size(params) + if _oid is None: + raise ValueError("No supported Elliptic Curve of size {params}") + else: + _oid = params + if _oid == EllipticCurveOID.Curve25519: if any(c != 0 for c in self): # pragma: no cover raise PGPError("Key is already populated!") @@ -1614,7 +1583,7 @@ def _generate(self, oid): ), 'little')) self._compute_chksum() else: - ECDSAPriv._generate(self, oid) + ECDSAPriv._generate(self, _oid) self.kdf.halg = self.oid.kdf_halg self.kdf.encalg = self.oid.kek_alg diff --git a/pgpy/packet/packets.py b/pgpy/packet/packets.py index cd494137..08c3e8d5 100644 --- a/pgpy/packet/packets.py +++ b/pgpy/packet/packets.py @@ -168,10 +168,14 @@ def encrypter_bin(self, val): def pkalg(self): return self._pkalg - @pkalg.register(int) - @pkalg.register(PubKeyAlgorithm) - def pkalg_int(self, val): - self._pkalg = PubKeyAlgorithm(val) + @pkalg.register + def pkalg_int(self, val: int) -> None: + if isinstance(val, PubKeyAlgorithm): + self._pkalg = val + else: + self._pkalg = PubKeyAlgorithm(val) + if self._pkalg is PubKeyAlgorithm.Invalid: + self._opaque_pkalg: int = val _c = {PubKeyAlgorithm.RSAEncryptOrSign: RSACipherText, PubKeyAlgorithm.RSAEncrypt: RSACipherText, @@ -192,7 +196,10 @@ def __bytearray__(self): _bytes = bytearray() _bytes += super(PKESessionKeyV3, self).__bytearray__() _bytes += binascii.unhexlify(self.encrypter.encode()) - _bytes += bytearray([self.pkalg]) + if self.pkalg == PubKeyAlgorithm.Invalid: + _bytes.append(self._opaque_pkalg) + else: + _bytes.append(self.pkalg) _bytes += self.ct.__bytearray__() if self.ct is not None else b'\x00' * (self.header.length - 10) return _bytes @@ -201,6 +208,8 @@ def __copy__(self): sk.header = copy.copy(self.header) sk._encrypter = self._encrypter sk.pkalg = self.pkalg + if self.pkalg == PubKeyAlgorithm.Invalid: + sk._opaque_pkalg = self._opaque_pkalg if self.ct is not None: sk.ct = copy.copy(self.ct) @@ -281,7 +290,7 @@ def parse(self, packet): self.ct.parse(packet) else: # pragma: no cover - del packet[:(self.header.length - 18)] + del packet[:(self.header.length - 10)] class Signature(VersionedPacket): @@ -350,13 +359,17 @@ def sigtype_int(self, val): self._sigtype = SignatureType(val) @sdproperty - def pubalg(self): + def pubalg(self) -> PubKeyAlgorithm: return self._pubalg - @pubalg.register(int) - @pubalg.register(PubKeyAlgorithm) - def pubalg_int(self, val): - self._pubalg = PubKeyAlgorithm(val) + @pubalg.register + def pubalg_int(self, val: int) -> None: + if isinstance(val, PubKeyAlgorithm): + self._pubalg: PubKeyAlgorithm = val + else: + self._pubalg = PubKeyAlgorithm(val) + if self._pubalg is PubKeyAlgorithm.Unknown: + self._opaque_pubalg: int = val sigs = { PubKeyAlgorithm.RSAEncryptOrSign: RSASignature, @@ -370,17 +383,17 @@ def pubalg_int(self, val): self.signature = sigs.get(self.pubalg, OpaqueSignature)() @sdproperty - def halg(self): + def halg(self) -> HashAlgorithm: return self._halg - @halg.register(int) - @halg.register(HashAlgorithm) - def halg_int(self, val): - try: - self._halg = HashAlgorithm(val) - - except ValueError: # pragma: no cover + @halg.register + def halg_int(self, val: int) -> None: + if isinstance(val, HashAlgorithm): self._halg = val + else: + self._halg = HashAlgorithm(val) + if self._halg is HashAlgorithm.Unknown: + self._opaque_halg = val @property def signature(self): @@ -407,8 +420,14 @@ def __bytearray__(self): _bytes = bytearray() _bytes += super(Signature, self).__bytearray__() _bytes += self.int_to_bytes(self.sigtype) - _bytes += self.int_to_bytes(self.pubalg) - _bytes += self.int_to_bytes(self.halg) + if self.pubalg is PubKeyAlgorithm.Unknown: + _bytes.append(self._opaque_pubalg) + else: + _bytes.append(self.pubalg) + if self.halg is HashAlgorithm.Unknown: + _bytes.append(self._opaque_halg) + else: + _bytes.append(self.halg) _bytes += self.subpackets.__bytearray__() _bytes += self.hash2 _bytes += self.signature.__bytearray__() @@ -432,8 +451,14 @@ def canonical_bytes(self): _body = bytearray() _body += self.int_to_bytes(self.header.version) _body += self.int_to_bytes(self.sigtype) - _body += self.int_to_bytes(self.pubalg) - _body += self.int_to_bytes(self.halg) + if self.pubalg is PubKeyAlgorithm.Unknown: + _body.append(self._opaque_pubalg) + else: + _body.append(self.pubalg) + if self.halg is HashAlgorithm.Unknown: + _body.append(self._opaque_halg) + else: + _body.append(self.halg) _body += self.subpackets.__hashbytearray__() _body += self.int_to_bytes(0, minlen=2) # empty unhashed subpackets _body += self.hash2 @@ -449,7 +474,11 @@ def __copy__(self): spkt.header = copy.copy(self.header) spkt._sigtype = self._sigtype spkt._pubalg = self._pubalg + if self._pubalg is PubKeyAlgorithm.Unknown: + spkt._opaque_pubalg = self._opaque_pubalg spkt._halg = self._halg + if self._halg is HashAlgorithm.Unknown: + spkt._opaque_halg = self._opaque_halg spkt.subpackets = copy.copy(self.subpackets) spkt.hash2 = copy.copy(self.hash2) @@ -678,17 +707,17 @@ def pubalg_int(self, val): self.signature = DSASignature() @sdproperty - def halg(self): + def halg(self) -> HashAlgorithm: return self._halg - @halg.register(int) - @halg.register(HashAlgorithm) - def halg_int(self, val): - try: - self._halg = HashAlgorithm(val) - - except ValueError: # pragma: no cover + @halg.register + def halg_int(self, val: int) -> None: + if isinstance(val, HashAlgorithm): self._halg = val + else: + self._halg = HashAlgorithm(val) + if self._halg is HashAlgorithm.Unknown: + self._opaque_halg: int = val @sdproperty def signer(self): @@ -715,7 +744,10 @@ def __bytearray__(self): _bytes = bytearray() _bytes += super(OnePassSignatureV3, self).__bytearray__() _bytes += bytearray([self.sigtype]) - _bytes += bytearray([self.halg]) + if self.halg is HashAlgorithm.Unknown: + _bytes.append(self._opaque_halg) + else: + _bytes.append(self.halg) _bytes += bytearray([self.pubalg]) _bytes += binascii.unhexlify(self.signer.encode("latin-1")) _bytes += bytearray([int(self.nested)]) @@ -776,13 +808,17 @@ def created_bin(self, val): self.created = self.bytes_to_int(val) @sdproperty - def pkalg(self): + def pkalg(self) -> PubKeyAlgorithm: return self._pkalg - @pkalg.register(int) - @pkalg.register(PubKeyAlgorithm) - def pkalg_int(self, val): - self._pkalg = PubKeyAlgorithm(val) + @pkalg.register + def pkalg_int(self, val: int) -> None: + if isinstance(val, PubKeyAlgorithm): + self._pkalg: PubKeyAlgorithm = val + else: + self._pkalg = PubKeyAlgorithm(val) + if self._pkalg is PubKeyAlgorithm.Unknown: + self._opaque_pkalg: int = val _c = { # True means public @@ -838,7 +874,10 @@ def fingerprint(self): # c) timestamp of key creation (4 octets); fp.update(self.int_to_bytes(calendar.timegm(self.created.timetuple()), 4)) # d) algorithm (1 octet): 17 = DSA (example); - fp.update(self.int_to_bytes(self.pkalg)) + if self.pkalg is PubKeyAlgorithm.Unknown: + fp.update(bytes([self._opaque_pkalg])) + else: + fp.update(self.int_to_bytes(self.pkalg)) # e) Algorithm-specific fields. fp.update(self.keymaterial.__bytearray__()[:plen]) @@ -855,7 +894,10 @@ def __bytearray__(self): _bytes = bytearray() _bytes += super(PubKeyV4, self).__bytearray__() _bytes += self.int_to_bytes(calendar.timegm(self.created.timetuple()), 4) - _bytes += self.int_to_bytes(self.pkalg) + if self.pkalg is PubKeyAlgorithm.Unknown: + _bytes.append(self._opaque_pkalg) + else: + _bytes.append(self.pkalg) _bytes += self.keymaterial.__bytearray__() return _bytes @@ -863,7 +905,10 @@ def __copy__(self): pk = self.__class__() pk.header = copy.copy(self.header) pk.created = self.created - pk.pkalg = self.pkalg + if self.pkalg is PubKeyAlgorithm.Unknown: + pk.pkalg = self._opaque_pkalg + else: + pk.pkalg = self.pkalg pk.keymaterial = copy.copy(self.keymaterial) return pk diff --git a/pgpy/pgp.py b/pgpy/pgp.py index f34a25fb..457d43dd 100644 --- a/pgpy/pgp.py +++ b/pgpy/pgp.py @@ -20,9 +20,12 @@ from datetime import datetime, timezone +from typing import Any, List, Optional, Union + from cryptography.hazmat.primitives import hashes from .constants import CompressionAlgorithm +from .constants import EllipticCurveOID from .constants import Features from .constants import HashAlgorithm from .constants import ImageEncoding @@ -79,6 +82,7 @@ from .types import SorteDeque __all__ = ['PGPSignature', + 'PGPSignatures', 'PGPUID', 'PGPMessage', 'PGPKey', @@ -592,6 +596,59 @@ def parse(self, packet): raise ValueError('Expected: Signature. Got: {:s}'.format(pkt.__class__.__name__)) +class PGPSignatures(collections_abc.Container, collections_abc.Iterable, collections_abc.Sized, Armorable, PGPObject): + '''OpenPGP detached signatures can often contain more than one signature in them.''' + + def __init__(self, signatures: List[PGPSignature] = []) -> None: + super().__init__() + self._sigs: List[PGPSignature] = signatures + + def __contains__(self, thing: Any) -> bool: + if not isinstance(thing, PGPSignature): + raise TypeError(f'PGPSignatures only contains a PGPSignature, not {type(thing)}') + return thing in self._sigs + + def __len__(self) -> int: + return len(self._sigs) + + def __iter__(self) -> collections_abc.Iterator[PGPSignature]: + for sig in self._sigs: + yield sig + + @property + def magic(self) -> str: + return "SIGNATURE" + + def __bytearray__(self) -> bytearray: + b = bytearray() + for sig in self._sigs: + b += sig.__bytearray__() + return b + + def parse(self, packet: bytes) -> None: + unarmored = self.ascii_unarmor(packet) + data = unarmored['body'] + + if unarmored['magic'] is not None and unarmored['magic'] != 'SIGNATURE': + raise ValueError(f"Expected: SIGNATURE. Got: {format(str(unarmored['magic']))}") + + if unarmored['headers'] is not None: + self.ascii_headers = unarmored['headers'] + + while data: + pkt = Packet(data) + if pkt.header.tag == PacketTag.Signature: + if isinstance(pkt, Opaque): + # skip unrecognized version. + pass + else: + sig = PGPSignature() + sig._signature = pkt + self._sigs.append(sig) + else: + raise ValueError(f"Expected: Signature. Got: {format(pkt.__class__.__name__)}") + + class PGPUID(ParentRef): @property def __sig__(self): @@ -1077,6 +1134,10 @@ def __or__(self, other): self._signatures += other._signatures return self + if isinstance(other, Opaque): + # ignore opaque packets + return self + raise NotImplementedError(str(type(other))) def __copy__(self): @@ -1153,9 +1214,9 @@ def new(cls, message, **kwargs): # message is definitely UTF-8 already format = 'u' - elif cls.is_ascii(message): + elif cls.is_utf8(message): # message is probably text - format = 't' + format = 'u' else: # message is probably binary @@ -1176,9 +1237,6 @@ def new(cls, message, **kwargs): lit.mtime = mtime lit.format = format - # if cls.is_ascii(message): - # lit.format = 't' - lit.update_hlen() msg |= lit @@ -1460,12 +1518,14 @@ def key_algorithm(self): return self._key.pkalg @property - def key_size(self): + def key_size(self) -> Optional[Union[int, EllipticCurveOID]]: """ The size pertaining to this key. ``int`` for non-EC key algorithms; :py:obj:`constants.EllipticCurveOID` for EC keys. .. versionadded:: 0.4.1 """ + if self._key is None: + return None if self.key_algorithm in {PubKeyAlgorithm.ECDSA, PubKeyAlgorithm.ECDH, PubKeyAlgorithm.EdDSA}: return self._key.keymaterial.oid # check if keymaterial is not an Opaque class containing a bytearray diff --git a/pgpy/types.py b/pgpy/types.py index 187d3984..2270f7d5 100644 --- a/pgpy/types.py +++ b/pgpy/types.py @@ -17,6 +17,8 @@ from enum import EnumMeta from enum import IntEnum +from typing import Union, Optional, Dict + from .decorators import sdproperty from .errors import PGPError @@ -69,15 +71,27 @@ class Armorable(metaclass=abc.ABCMeta): """, flags=re.MULTILINE | re.VERBOSE) @property - def charset(self): + def charset(self) -> str: return self.ascii_headers.get('Charset', 'utf-8') @charset.setter - def charset(self, encoding): + def charset(self, encoding: str) -> None: self.ascii_headers['Charset'] = codecs.lookup(encoding).name @staticmethod - def is_ascii(text): + def is_utf8(text: Union[str, bytes, bytearray]) -> bool: + if isinstance(text, str): + return True + else: + try: + text.decode('utf-8') + return True + except UnicodeDecodeError: + return False + + @staticmethod + def is_ascii(text: Union[str, bytes, bytearray]) -> bool: + '''This is a deprecated, pointless method''' if isinstance(text, str): return bool(re.match(r'^[ -~\r\n\t]*$', text, flags=re.ASCII)) @@ -87,7 +101,7 @@ def is_ascii(text): raise TypeError("Expected: ASCII input of type str, bytes, or bytearray") # pragma: no cover @staticmethod - def is_armor(text): + def is_armor(text: Union[str, bytes, bytearray]) -> bool: """ Whether the ``text`` provided is an ASCII-armored PGP block. :param text: A possible ASCII-armored PGP block. @@ -95,12 +109,15 @@ def is_armor(text): :returns: Whether the text is ASCII-armored. """ if isinstance(text, (bytes, bytearray)): # pragma: no cover - text = text.decode('latin-1') + try: + text = text.decode('utf-8') + except UnicodeDecodeError: + return False return Armorable.__armor_regex.search(text) is not None @staticmethod - def ascii_unarmor(text): + def ascii_unarmor(text: Union[str, bytes, bytearray]) -> Dict[str, Optional[Union[str, bytes, bytearray]]]: """ Takes an ASCII-armored PGP block and returns the decoded byte value. @@ -111,7 +128,7 @@ def ascii_unarmor(text): It can contain the following keys: ``magic``, ``headers``, ``hashes``, ``cleartext``, ``body``, ``crc``. """ m = {'magic': None, 'headers': None, 'body': bytearray(), 'crc': None} - if not Armorable.is_ascii(text): + if not Armorable.is_utf8(text): m['body'] = bytearray(text) return m @@ -731,6 +748,7 @@ def __repr__(self): class SorteDeque(collections.deque): """A deque subclass that tries to maintain sorted ordering using bisect""" + def insort(self, item): i = bisect.bisect_left(self, item) self.rotate(- i) diff --git a/requirements.txt b/requirements.txt index e2a25384..6bc0dd57 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1 @@ cryptography>=3.3.2 -pyasn1 diff --git a/setup.cfg b/setup.cfg index af26cfdd..c7691a75 100644 --- a/setup.cfg +++ b/setup.cfg @@ -42,7 +42,6 @@ packages = # TODO: fix support for cryptography >= 38.0.0 (https://github.com/SecurityInnovation/PGPy/issues/402) install_requires = cryptography>=3.3.2 - pyasn1 python_requires = >=3.6 # doc_requires = diff --git a/tests/test_05_actions.py b/tests/test_05_actions.py index 8a801c9c..186bc2f3 100644 --- a/tests/test_05_actions.py +++ b/tests/test_05_actions.py @@ -20,7 +20,6 @@ from pgpy import PGPMessage from pgpy import PGPSignature from pgpy import PGPUID -from pgpy._curves import _openssl_get_supported_curves from pgpy.constants import CompressionAlgorithm from pgpy.constants import EllipticCurveOID from pgpy.constants import Features @@ -288,7 +287,7 @@ def test_add_subkey(self, pkspec, skspec): if not alg.can_gen: pytest.xfail('Key algorithm {} not yet supported'.format(alg.name)) - if isinstance(size, EllipticCurveOID) and ((not size.can_gen) or size.curve.name not in _openssl_get_supported_curves()): + if isinstance(size, EllipticCurveOID) and (not size.can_gen): pytest.xfail('Curve {} not yet supported'.format(size.curve.name)) key = self.keys[pkspec] @@ -511,7 +510,7 @@ def test_revoke_subkey(self, pkspec, skspec): if not alg.can_gen: pytest.xfail('Key algorithm {} not yet supported'.format(alg.name)) - if isinstance(size, EllipticCurveOID) and ((not size.can_gen) or size.curve.name not in _openssl_get_supported_curves()): + if isinstance(size, EllipticCurveOID) and (not size.can_gen): pytest.xfail('Curve {} not yet supported'.format(size.curve.name)) # revoke the subkey diff --git a/tests/test_06_compatibility.py b/tests/test_06_compatibility.py new file mode 100644 index 00000000..8ffec7a1 --- /dev/null +++ b/tests/test_06_compatibility.py @@ -0,0 +1,58 @@ +# coding=utf-8 +""" ensure that we don't crash on surprising messages +""" +import pytest + +from pgpy import PGPKey, PGPMessage, PGPSignatures +from pgpy.constants import SecurityIssues +import glob + +class TestPGP_Compatibility(object): + # test compatibility: + # - Armored object with (non-ASCII) UTF-8 comments + # - signatures with unknown pubkey algorithms + # - certs with certifications from unknown algorithms + # - certs with subkeys with unknown algorithms + # - certs with ECC subkeys with unknown curves + # - encrypted messages with surprising parts + def test_import_unicode_armored_cert(self) -> None: + k:PGPKey + (k, _) = PGPKey.from_file('tests/testdata/compatibility/ricarda.pgp') + assert k.check_soundness() == SecurityIssues.OK + + @pytest.mark.parametrize('sig', glob.glob('*.sig', root_dir='tests/testdata/compatibility')) + def test_bob_sig_from_multisig(self, sig:str)-> None: + k:PGPKey + (k, _) = PGPKey.from_file('tests/testdata/compatibility/bob.pgp') + msg = 'Hello World :)' + sigs = PGPSignatures.from_file(f'tests/testdata/compatibility/{sig}') + verif:Optional[pgpy.SignatureVerification] = None + for sig in sigs: + if sig.signer == k.fingerprint.keyid: + verif = k.verify(msg, sig) + assert verif is not None + + def test_cert_unknown_algo(self) -> None: + k:PGPKey + (k, _) = PGPKey.from_file('tests/testdata/compatibility/bob_with_unknown_alg_certification.pgp') + assert k.check_soundness() == SecurityIssues.OK + + def test_cert_unknown_subkey_algo(self) -> None: + k:PGPKey + (k, _) = PGPKey.from_file('tests/testdata/compatibility/bob_with_unknown_subkey_algorithm.pgp') + assert k.check_soundness() == SecurityIssues.OK + + @pytest.mark.parametrize('flavor', ['ecdsa', 'eddsa', 'ecdh']) + def test_cert_unknown_curve(self, flavor:str) -> None: + k:PGPKey + (k, _) = PGPKey.from_file(f'tests/testdata/compatibility/bob_with_unknown_{flavor}_curve.pgp') + assert k.check_soundness() == SecurityIssues.OK + + @pytest.mark.parametrize('msg', glob.glob('*.msg', root_dir='tests/testdata/compatibility')) + def test_unknown_message(self, msg:str)-> None: + k:PGPKey + (k, _) = PGPKey.from_file('tests/testdata/compatibility/bob-key.pgp') + msg:PGPMessage = PGPMessage.from_file(f'tests/testdata/compatibility/{msg}') + cleartext:PGPMessage = k.decrypt(msg) + assert not cleartext.is_encrypted + assert cleartext.message.startswith(b'Encrypted') diff --git a/tests/test_10_exceptions.py b/tests/test_10_exceptions.py index 299f3456..0e6cf182 100644 --- a/tests/test_10_exceptions.py +++ b/tests/test_10_exceptions.py @@ -139,8 +139,8 @@ class WhatException(Exception): pass # unexpected signature type fuzz_pkt(3, 0x7f, PGPError) - # unexpected pubkey algorithm - fuzz_pkt(4, 0x64, PGPError) + # unexpected pubkey algorithm -- does not raise an exception during parsing + fuzz_pkt(4, 0x64, None) # unexpected hash algorithm - does not raise an exception during parsing fuzz_pkt(5, 0x64, None) diff --git a/tests/testdata/compatibility/bob-key.pgp b/tests/testdata/compatibility/bob-key.pgp new file mode 100644 index 00000000..59e981b7 --- /dev/null +++ b/tests/testdata/compatibility/bob-key.pgp @@ -0,0 +1,82 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- +Comment: Bob's OpenPGP Transferable Secret Key + +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 +=miES +-----END PGP PRIVATE KEY BLOCK----- diff --git a/tests/testdata/compatibility/bob.pgp b/tests/testdata/compatibility/bob.pgp new file mode 100644 index 00000000..b58b8c3a --- /dev/null +++ b/tests/testdata/compatibility/bob.pgp @@ -0,0 +1,42 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Comment: Bob's OpenPGP certificate + +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 +NEJd3XZRzaXZE2aAMQ== +=NXei +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/testdata/compatibility/bob_with_unknown_alg_certification.pgp b/tests/testdata/compatibility/bob_with_unknown_alg_certification.pgp new file mode 100644 index 00000000..3707582d --- /dev/null +++ b/tests/testdata/compatibility/bob_with_unknown_alg_certification.pgp @@ -0,0 +1,50 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +5KjhX2PVNEJd3XZRzaXZE2aAMQ== +=WSi3 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/testdata/compatibility/bob_with_unknown_ecdh_curve.pgp b/tests/testdata/compatibility/bob_with_unknown_ecdh_curve.pgp new file mode 100644 index 00000000..4d61f469 --- /dev/null +++ b/tests/testdata/compatibility/bob_with_unknown_ecdh_curve.pgp @@ -0,0 +1,40 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +MF4/9Ikup96bHiodjzRzjg== +=4wyr +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/testdata/compatibility/bob_with_unknown_ecdsa_curve.pgp b/tests/testdata/compatibility/bob_with_unknown_ecdsa_curve.pgp new file mode 100644 index 00000000..baabb928 --- /dev/null +++ b/tests/testdata/compatibility/bob_with_unknown_ecdsa_curve.pgp @@ -0,0 +1,40 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +8U1sStGbL6xCqoC7 +=F3Jy +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/testdata/compatibility/bob_with_unknown_eddsa_curve.pgp b/tests/testdata/compatibility/bob_with_unknown_eddsa_curve.pgp new file mode 100644 index 00000000..1885531b --- /dev/null +++ b/tests/testdata/compatibility/bob_with_unknown_eddsa_curve.pgp @@ -0,0 +1,40 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +rGbptmnWtUt/BkSu +=rsWG +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/testdata/compatibility/bob_with_unknown_subkey_algorithm.pgp b/tests/testdata/compatibility/bob_with_unknown_subkey_algorithm.pgp new file mode 100644 index 00000000..4802a8ce --- /dev/null +++ b/tests/testdata/compatibility/bob_with_unknown_subkey_algorithm.pgp @@ -0,0 +1,45 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +GayI21FEA+d9JQ+3rFmecxxZ +=z8mg +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/testdata/compatibility/encrypted_signed_with_unknown_algorithm.msg b/tests/testdata/compatibility/encrypted_signed_with_unknown_algorithm.msg new file mode 100644 index 00000000..0c789821 --- /dev/null +++ b/tests/testdata/compatibility/encrypted_signed_with_unknown_algorithm.msg @@ -0,0 +1,23 @@ +-----BEGIN PGP MESSAGE----- + +wcDMA3wvqk35PDeyAQv+OGc6ftXom/H7P7G/pg6XUaDdAJ4aWqvKprWyoJ+nlqC2 +ZTjhRab15GGKDPNgcCVVB8X+Q45fsWx5QojlcTlshwB9pSd0/JlbBsYQQYNIJZCb +YiiNky+TA/7o4k2QXJI11qj4Vk9AAj7g2QxmmQFvL0CwGCpFMLsYVewbZySrLLA8 +AJ09iwDt/vldyPHeLc0rU3H+kAO+VbFgV97uOnR/8zymjoI42oWxfs7GIhEkq/Md +2x+ssvFvBejxXWS3dJ8DH3HW1hc0gTp2aBjoPb9oJP8UCGjw0vVG7PUWsnpKuKOX +6x6xFXiqgJZzDVj/lgJjUopvlRb0iXa0K7aDb2dClFV8pyOM+YBr7cmVZrD/cMya +aTqmgVBN4bIF9B89Bguma9hMpIeODeI8ZmImhNy60QE767UteosIakh+HhdpmVMz +9ZkeALj+MjXZLZnCCRcMcxsCLvX0rkGQFPAEzxbli+POj2Kln6mIntcu5d0IZjMi +NQwnKHm4IurwOuYsfXw00sEWAWIMiWBTtRsBrjQT5WZkTHFLAObXDPJJ9tKC/znX +ooTA1IKzpyoejDMZ1BC5899UaZR/WhoKHAKrLz9SnDC2fy1JhQFRXJsv+XdFSaSl +bzG2nQoCyZ+BFeSIJSdUxeARLDH/w4lgPeMTaqfs4P0V2Han483sjlVeJQ9BkCrx +2VwaxzdTvpvqb7BbZLXm4Fi+AlXZNHGjXZVf5PxfTBnQAqor1DWT0YVs1W3MAGHe +mtEdxex0kdZeSvI2JQJGuWdQR+q/hiiv9P0tymMPlEYhJ3oLsKoBrMZCvFvMXen3 +LpGEzUuYBH9A8PpjLYF7LeUDYCpQlM+2tnw3q68S0L6fEAt2kwI9XvLZmbOeLwDs +rrjyZ8tDb43xeBxMF3f2YRGUmuDEQyXgLWMBkUlN8C+MIJaenVwWUt7okt9Bzrrs +HoUozWdL7/f61utrkLrEcvuyBdm8f756+Tp9Pgwk3x8v69BET8d6ExYzq84sxLq/ +YR4YOzAuYzxwThjZo9kKD+C19vq05nz0BLblDK370y0sx4dJfCQiW/XDcTSEdTuh +1y3tFvtbOhBe7W7WxyBM8NrnbGyT169Ynd8MHZcjfT4rdg3vEMK8iJ5wUHiXYO3q +r6OGxt5iiVg= +=tj4l +-----END PGP MESSAGE----- diff --git a/tests/testdata/compatibility/encrypted_signed_with_unknown_signature_version.msg b/tests/testdata/compatibility/encrypted_signed_with_unknown_signature_version.msg new file mode 100644 index 00000000..4f8ee703 --- /dev/null +++ b/tests/testdata/compatibility/encrypted_signed_with_unknown_signature_version.msg @@ -0,0 +1,25 @@ +-----BEGIN PGP MESSAGE----- + +wcDMA3wvqk35PDeyAQv9FLXg7nalbJA17Pbd4otaD1beLSJ1tf9zWv6aKGoMclPS +sWJMvfW4ojBH2jJuH7HUenyPWMsnJIzeP8YC8jWF+vnVn6CVB0Hnef8+YNOF0K5T +jj+/lIKOxGPgUUo9hL7h+UI0a/W1noggmwgG2D5SgfQ7enyDk0uw/vpk5wRwqRzF +765O97izaUyBhkx7snls9dwrFPduwuvAYTnt2NbeaSJeivj+0N+YYPGqiXL5pWqn +WdPkCY0EPMIRDgco1rHOP2qUDKXN224OeJiCWE/sHlpmwyPE6P2L9WvazPD/pmBo +AI27TjejVvcmSDx45XNVu5ONRZ7pHerrURMKXb27nscfx4dj6MO4nSFqXiNN4uqy +mt1vF4ELEhu6OtQBXg3AlSj8EYQPkHI0nzEkOmWZrWMJU+at7Ph1BblhEQFiidOy +528BciZIvrLdvcWhgNiJ2eYxH3MXrnl/LKmeRtr1Zj1oJMxlpo47owq2vXc1fBIW +z88dDoN/PJgImGGzeHCY0sGYAUTo/Bd+MIiH/lTJUxUU4UfmYRTsD+R18CLLVhB9 +cIysmxlXbbvQAiSTY2t409rELyfJQU1A7D9Y0JwIou/njkIsrufOUGF936ZFN9T1 +WQUzbnyHqEeOsA6No/qk2SNVNgdGPv9emE5TX/rUQkonC0/zpPIedEY2fiBVNxkj +mvALMs97sIWcle/Vt3qPHZCV9xNtajg0qOZvmPtS+dnipqoe+1T7GEjO9xOwEHjZ +LGrSfbGAmvzNEJnfiX9rl2qAe7NaXiIDHVHQkY31DLihrjlX+6mJtHeqKVOQW1Ru +yvl4yBAuu0mxOQahRGmNRdYlUHnyYXJHLoXljJvNUCsH43r2KGeaDk9i4kDQA4pG +qqEyqOCUk94nKA/FhSf8247nubHRGyf3Sa0OXa7h8QvEtVqS+cBV3vjDhFVkFTLu +/pEDimiy267XDF5nLwwVHrLavT4VeGc9w7SoACBYvDspvt8RgCT3gnG2S3vtxgvw +8OzoDR8TATk/wKwEav5WI35ElfrnM60Erde5XZH5R1YiWFKOMqDe16YU4c4tZa7Y +dWcfaSFfOUm7ekAuCkOQx024L91c2wVdJY18ZGvR6I3XhaAbj0+a7ksT4UU1eNLX +qfGJjafpwNqPyKdSSVc7jxxsY4v8B24rtrWDOgBbRp1j8JSmtmSVB3rz39Gq4aLn +yuy/kZPgsNuaLzDvZ06/iWdGgHPcLAhz7orU++epxLK6xKgs/mjSanp0UYWZjx2d +AO1qJiiABKSJn1krOid7pezsOLxkN4rKNJ2rpuFZKuUeChVzDqZF7S/f +=V8p/ +-----END PGP MESSAGE----- diff --git a/tests/testdata/compatibility/pkesk_unknown_pkalg.msg b/tests/testdata/compatibility/pkesk_unknown_pkalg.msg new file mode 100644 index 00000000..04d70f8b --- /dev/null +++ b/tests/testdata/compatibility/pkesk_unknown_pkalg.msg @@ -0,0 +1,20 @@ +-----BEGIN PGP MESSAGE----- + +wcDMA3wvqk35PDeyAQv+PkvYwtAPmEyGugGzZ3FvqGzxQ9kVm0N2+VjJ0VBMoWpz +jE6UB6rXXnBbaCCeiXiTKGTNOueyXB09xZVUxa1Kub4yTA90d+NxU7YFhUvcEzt+ +LgP9oWe3MrKB+WOFA7z9RAwCgfvBzwYZ9AFO/v4UHQVrDL7KLLnglPtcXnrvMf7G +ecqcoHAbyj/Jn4ZQqL1/fVF3Dqkfrv+M307IJtfh/SebMxAnYNDi/5U9xnZo/Bvf +JVGa2UtxrvyMkIbZZuy82ZzkDK1HI+NHQhBlksS00AKA/vIwTHKNsdITE+ToY7Pi +jjRU92Sl1KyKdt8e00DTPoDRWxxUFSVMJB4eSP/39HBcAVGW5tHYkMGYXhwRoxPD +qbxWawGfrLxCNga0n5cM3Z1I4m8jel1Xj0RvjWptgHYGB64oWte9hfh3GHT7o3X6 +40zJnsCrp6BFyY+lp7DHTsyOGCh6qxA+jvcu0UBMn+mSEkWmyP318KEN2ohJZzWt +rWzU709sTOgZDI1qqMbLwcBKAwEjRWeJq83vYxoaGhoaGhoaGhoaGhoaGhoaGhoa +GhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoa +GhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoa +GhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoa +GhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoa +GhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhrSTAHK +7+Hdple30q0bt73f41f61wdFRUYmyREN1zmOt8NWLUIdQFkeY1fw25Nil2yH3h+/ +spp41fwEYgEStCN2jv7rb4AvPlNcCb929/c= +=Gt9v +-----END PGP MESSAGE----- diff --git a/tests/testdata/compatibility/pkesk_unknown_version.msg b/tests/testdata/compatibility/pkesk_unknown_version.msg new file mode 100644 index 00000000..75b9f7fe --- /dev/null +++ b/tests/testdata/compatibility/pkesk_unknown_version.msg @@ -0,0 +1,16 @@ +-----BEGIN PGP MESSAGE----- + +wcDMA3wvqk35PDeyAQv+PkvYwtAPmEyGugGzZ3FvqGzxQ9kVm0N2+VjJ0VBMoWpz +jE6UB6rXXnBbaCCeiXiTKGTNOueyXB09xZVUxa1Kub4yTA90d+NxU7YFhUvcEzt+ +LgP9oWe3MrKB+WOFA7z9RAwCgfvBzwYZ9AFO/v4UHQVrDL7KLLnglPtcXnrvMf7G +ecqcoHAbyj/Jn4ZQqL1/fVF3Dqkfrv+M307IJtfh/SebMxAnYNDi/5U9xnZo/Bvf +JVGa2UtxrvyMkIbZZuy82ZzkDK1HI+NHQhBlksS00AKA/vIwTHKNsdITE+ToY7Pi +jjRU92Sl1KyKdt8e00DTPoDRWxxUFSVMJB4eSP/39HBcAVGW5tHYkMGYXhwRoxPD +qbxWawGfrLxCNga0n5cM3Z1I4m8jel1Xj0RvjWptgHYGB64oWte9hfh3GHT7o3X6 +40zJnsCrp6BFyY+lp7DHTsyOGCh6qxA+jvcu0UBMn+mSEkWmyP318KEN2ohJZzWt +rWzU709sTOgZDI1qqMbLwUoXQUFBQUFBQUEJYWFhYWFhYWFhYWFhYWFhYWFhYWFh +YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYdJMAcrv +4d2mV7fSrRu3vd/jV/rXB0VFRibJEQ3XOY63w1YtQh1AWR5jV/Dbk2KXbIfeH7+y +mnjV/ARiARK0I3aO/utvgC8+U1wJv3b39w== +=DN9X +-----END PGP MESSAGE----- diff --git a/tests/testdata/compatibility/ricarda.pgp b/tests/testdata/compatibility/ricarda.pgp new file mode 100644 index 00000000..e0a5fb25 --- /dev/null +++ b/tests/testdata/compatibility/ricarda.pgp @@ -0,0 +1,86 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Comment: 2ADE 0F8A A059 6BC9 4E50 D2AD 9162 53AB 652E F195 +Comment: Ricarda S. Álvarez + +xsDNBGJvrDABDACrZUY7VU1uZ/uzntlAKEHVF4mb3eYSdW1rE3hVke0HoDvtQbzq +KQ9qgfPaNwdkxRexgrNGSeKkQJcgR7gMWxFxM/FwddQIXfVL43nRlN+iGvFDYR+9 +dn5gSOD9EvZUYLN9p6yR3Umyglt4NpdjYM0J+Rn2DVyfGHCtS+z1fdym1h1zdImo +rArBpWMEdvNN/6dR8BN67WSBs5pVsvnDPdjbeU+GPJVoRH4CWe/LdJnJDICPmlva +gAyeJeK+KitkxD8IIc9d18x5dV1Z/LL2o1B0Psort8+az2Z+NbkP2cUv0DDRyZIM +Ww1A6KMSSNuvewXGCU+gEFlGIA83zfq7XE3WNp9EPy9xCs610+KxSS9cftKdrMmU +cl37Gb1lZyLFIBUCwPdIyTvhs6r6rMgu4GQ46sPl8qeLbtaoXnPWj9V1Fn9RoMgz +Kq8ZItFCJfCbf+gamx/0S/0mE47giuAtymw8Hf53e3jsSANK28GpcsEUNqWT4djb +YgcWl2iXR7n0i9cAEQEAAcLBSQQfAQoAfQWCYm+sMAMLCQcJEJFiU6tlLvGVRxQA +AAAAAB4AIHNhbHRAbm90YXRpb25zLnNlcXVvaWEtcGdwLm9yZ6O6vv9v4H1aAR9Z +aEksrL/2rQGm4Omv2SCubCC1pk/DAxUKCAKbAQIeARYhBCreD4qgWWvJTlDSrZFi +U6tlLvGVAACp1wv+MEkIs8x2Wk6e+i4rbclnkBjR2tSwv3N66jcz09QeDt5xwX1Q +jq1TP+XGFJfFA+LUugbLWNzWqwh7CypSc6IAB82+Ha+lCMjY3SZLfTe6crUgDWOZ +wDprVND6z2g9UlgJ6rfFf329LEUziknjKFBbreONH12tOzvCxrxipp84J0DZEqO3 +0VB2b2B7uO1X5V1aQMFj4JEafQ6Or6uXtR3Fwcs/JALwhqydy3LI4Y0s/y91qdPP +69DgugVDbG/Kkp5W2CNtGyd51cnEoFEbh9nV0hHR+rERU2ZcyoNfZQCyPuHMIT1L +PndcWLsT6Ga3TvXLUEhOOl6CPpox0aV7bsGpip0u54yGkhgR5YYLchcTVt15q5+/ +M5Z03et1LcSZKk1ijSFXNsOWdD2ojneN3vhlKbJoDosT10WyCsXKL8JNP4F4q4nU +22+/N1sttbgzSatwPxyiC7kKymQmDtg8NCyyCtpDoRkEIzaMv+4DqoMVkvLRcF1K +vX+rNEg1OxneqMSEzS1SaWNhcmRhIFMuIMOBbHZhcmV6IDxyaWNhcmRhQG9wZW5w +Z3AuZXhhbXBsZT7CwUwEEwEKAIAFgmJvrDADCwkHCRCRYlOrZS7xlUcUAAAAAAAe +ACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmfo22n7d9n+Nv3PxzMP93f7 +rejDV4BFsobH6T5cZGvj8AMVCggCmQECmwECHgEWIQQq3g+KoFlryU5Q0q2RYlOr +ZS7xlQAAu6EL/iJ91h1dwcQMZpbKYnBbH/1U/ncbIlhkQf8YzjrpzVprU0sr4cKu +mx42EylcteODVoDN8ITGROUC8Prw5tu+NS2mjkKWUlj56eLkpS3A3D6NqPIFEzU3 +KYztp+Y0hq2ZmsGsPgL1AbVPc2+ngUSL4pXgQ5hmVoD3B6VGqBReyKXhZNzH42S5 +fMuOsY8+/xgQ0WDwSCVeUW7Otql24iFji9U4eL036AzOO1hXkbOesrw4E7GmU2mR +kkX/aDZ9bGYT3yVZ/CJkU4wrUHJWW1IJl/bl//becL8Vnqr92vQkYQnUh19zIi2n +6ualROjcoITjjRemvkBfM9zXTd6kVFKD+ySDnGtNq62Ukz0/COg81tAnnnXeNhlP +1M8yA6zfrY17tAFYLmALUrPYjVy4ZJuaHScnIcM5lHIKYn1ijetGQSjI4sT/mSi4 +8fwNHFRufR7ta9XWv5b4+m8SAyrJ/FqnRoOwtoph0ZxSItjpv+qLPX2N4M8/JOqh +3QhI5ZDd+ScGJc7AzQRib6wwAQwArMv2IdO1f8a/brBc/+LeCqyqR+qLKzZRLAvF ++c6+qG7D9OzZCJfbPltnQ5BgRzIiSKgzDugDDt0m3fdWBxOQG5Ojo53Xu1ZTgRUD +0KWI4kH5Cs0gp3Kl62TdNAxNUlHdWqJ6G6WYVMlMhLmBVPjo65pT1+OON2v/O/qA +8ZJRlK3RyKym4Kcr8JbtX1roSRtVPRpi++Y1CGuhnK3UM68putqfgZOnTZxln2m2 +BUrL8fWgme2rTJyrrN8fSM61dZZ+5E0SWDMBxEp5bimMrRjJc7V0JMUx2HiCDe/l +panzleAugfEVUeAYsEe9C+7k3p2r00roL0dWnrMgfhGnJy5ccmPyzEQpoA6ARq1a +EBk2Syr/QNO93GfDFcK9pTcDcQdUgq93x5s9LShLQ7fuvVXXxkl4QkdKJn+Vb2yP +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 +=i+jK +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/testdata/compatibility/sig23_sig4.sig b/tests/testdata/compatibility/sig23_sig4.sig new file mode 100644 index 00000000..4710b31b --- /dev/null +++ b/tests/testdata/compatibility/sig23_sig4.sig @@ -0,0 +1,26 @@ +-----BEGIN PGP SIGNATURE----- + +wsE7FwABCgBvBYJkf2S3CRD7/MgqAV5zMEcUAAAAAAAeACBzYWx0QG5vdGF0aW9u +cy5zZXF1b2lhLXBncC5vcmeLydr/KwuIg2juO15I6oucMhsgNCcuFLmwzmRjN7WP +XxYhBNGmbhojsYLJmA94jPv8yCoBXnMwAACzwgwAsa09M/8lZf3EfRfcDzzwYKUq +kKkeyOdTGYZEw4Wr9q3bW+Ihl8EECzntzPkTObJjNfRjlB8VW+XGgSY4CoNVbihD +b/LN/9K35qqaJgp0Vw1w9KC0NcmWqykn+b3mmWcbHnxE9uEnG4QhCXIM9/u+O13o +eKoteXc+bSYa7eA6JJpO2cBxq/ZqG1CHp5x8+0QC2kiZllsmkZqgqCleF9M70Al/ +tk3OdnodsST5c2bwPkThnYJazEMBhHv2YPGLhwj6j0N+I+HTqloEZxd7gTcFsIDJ +haiBrRjQ9D5ePdpzNLPtemG79vxUeVpHniQAgkXHZqCct0S788kbMJC0hAOYWD/2 +AvmeI254FJqrd2ORdWoMFK1raAzRLWetj3ts4dcU/6Y36/AjMhN+zqPlxDrd3hXW +WadP9HQqgld8H3UG8cLDM7XdZRBqr5v2zwH9dgJTg/bVysKsg2LWm0m1k6rbd6EQ +m6ow6tOrgzvG7bsTbgvsWeOjlc55TrCONOK1+qpIwsE7BAABCgBvBYJkf2S3CRD7 +/MgqAV5zMEcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmeL +ydr/KwuIg2juO15I6oucMhsgNCcuFLmwzmRjN7WPXxYhBNGmbhojsYLJmA94jPv8 +yCoBXnMwAACzwgwAsa09M/8lZf3EfRfcDzzwYKUqkKkeyOdTGYZEw4Wr9q3bW+Ih +l8EECzntzPkTObJjNfRjlB8VW+XGgSY4CoNVbihDb/LN/9K35qqaJgp0Vw1w9KC0 +NcmWqykn+b3mmWcbHnxE9uEnG4QhCXIM9/u+O13oeKoteXc+bSYa7eA6JJpO2cBx +q/ZqG1CHp5x8+0QC2kiZllsmkZqgqCleF9M70Al/tk3OdnodsST5c2bwPkThnYJa +zEMBhHv2YPGLhwj6j0N+I+HTqloEZxd7gTcFsIDJhaiBrRjQ9D5ePdpzNLPtemG7 +9vxUeVpHniQAgkXHZqCct0S788kbMJC0hAOYWD/2AvmeI254FJqrd2ORdWoMFK1r +aAzRLWetj3ts4dcU/6Y36/AjMhN+zqPlxDrd3hXWWadP9HQqgld8H3UG8cLDM7Xd +ZRBqr5v2zwH9dgJTg/bVysKsg2LWm0m1k6rbd6EQm6ow6tOrgzvG7bsTbgvsWeOj +lc55TrCONOK1+qpI +=idy8 +-----END PGP SIGNATURE----- diff --git a/tests/testdata/compatibility/sig4_b-sig4_r.sig b/tests/testdata/compatibility/sig4_b-sig4_r.sig new file mode 100644 index 00000000..281dc097 --- /dev/null +++ b/tests/testdata/compatibility/sig4_b-sig4_r.sig @@ -0,0 +1,26 @@ +-----BEGIN PGP SIGNATURE----- + +wsE7BAABCgBvBYJkf2S3CRD7/MgqAV5zMEcUAAAAAAAeACBzYWx0QG5vdGF0aW9u +cy5zZXF1b2lhLXBncC5vcmeLydr/KwuIg2juO15I6oucMhsgNCcuFLmwzmRjN7WP +XxYhBNGmbhojsYLJmA94jPv8yCoBXnMwAACzwgwAsa09M/8lZf3EfRfcDzzwYKUq +kKkeyOdTGYZEw4Wr9q3bW+Ihl8EECzntzPkTObJjNfRjlB8VW+XGgSY4CoNVbihD +b/LN/9K35qqaJgp0Vw1w9KC0NcmWqykn+b3mmWcbHnxE9uEnG4QhCXIM9/u+O13o +eKoteXc+bSYa7eA6JJpO2cBxq/ZqG1CHp5x8+0QC2kiZllsmkZqgqCleF9M70Al/ +tk3OdnodsST5c2bwPkThnYJazEMBhHv2YPGLhwj6j0N+I+HTqloEZxd7gTcFsIDJ +haiBrRjQ9D5ePdpzNLPtemG79vxUeVpHniQAgkXHZqCct0S788kbMJC0hAOYWD/2 +AvmeI254FJqrd2ORdWoMFK1raAzRLWetj3ts4dcU/6Y36/AjMhN+zqPlxDrd3hXW +WadP9HQqgld8H3UG8cLDM7XdZRBqr5v2zwH9dgJTg/bVysKsg2LWm0m1k6rbd6EQ +m6ow6tOrgzvG7bsTbgvsWeOjlc55TrCONOK1+qpIwsE7BAABCgBvBYJkf2S3CRCz ++fFdlxFkrkcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmfZ +kjsbm6GUzqohKl3WhKgzzGl51pJBsREOkFBHTNhpeBYhBN9WS6uCrGY2n74Fz7P5 +8V2XEWSuAABShwwAo41bVBEuZPowTEL5uvvBL8eEPuS/+11ygXF/hfWayEAvIW+y +tUSLdQ2xF/SJLDGPgkwRcStpX2qIHK0qB4of3fG9OX95upcldKgmdrq38OWuti95 +IuZnuWQ75w0Ka8E/er/lvLmI6fW8istAvUkX1fSthQ1IYeEAPH4CEy0m5lwJfzK+ +XEF6Ne1rEBig6+LC+5/VyBI0jPWhW99g7kH5PiusSFdllO2Ewsfe7GXbWpqwJwCs +DqrdyCgh9z9lt7rTKwpbg2aSPKqKk8DGz2FPjmFgz5WyYWiCG28oTmBDHXhN5i5X ++pPXOlwSvUiGmrvZswewbA4qfBX8jLwqmH/5VaNAiegS05MjTsYEtgAjogCAW3kv +9ka2bOnw6r6GWBiKebE2JU8my+B0H07o9NJ561r7qfyrclF/610z5b6Jh/v6jbCj +2ZCkDTCxyXu4z7IbMY2bPW09QfaW4bYlsfehcwJRuDtxekFbS73mmo9nhVXPhG9s +5I3wawEahPoXGOVn +=QY9Z +-----END PGP SIGNATURE----- diff --git a/tests/testdata/compatibility/sig4_r-sig4_b.sig b/tests/testdata/compatibility/sig4_r-sig4_b.sig new file mode 100644 index 00000000..b8240c63 --- /dev/null +++ b/tests/testdata/compatibility/sig4_r-sig4_b.sig @@ -0,0 +1,26 @@ +-----BEGIN PGP SIGNATURE----- + +wsE7BAABCgBvBYJkf2S3CRCz+fFdlxFkrkcUAAAAAAAeACBzYWx0QG5vdGF0aW9u +cy5zZXF1b2lhLXBncC5vcmfZkjsbm6GUzqohKl3WhKgzzGl51pJBsREOkFBHTNhp +eBYhBN9WS6uCrGY2n74Fz7P58V2XEWSuAABShwwAo41bVBEuZPowTEL5uvvBL8eE +PuS/+11ygXF/hfWayEAvIW+ytUSLdQ2xF/SJLDGPgkwRcStpX2qIHK0qB4of3fG9 +OX95upcldKgmdrq38OWuti95IuZnuWQ75w0Ka8E/er/lvLmI6fW8istAvUkX1fSt +hQ1IYeEAPH4CEy0m5lwJfzK+XEF6Ne1rEBig6+LC+5/VyBI0jPWhW99g7kH5Pius +SFdllO2Ewsfe7GXbWpqwJwCsDqrdyCgh9z9lt7rTKwpbg2aSPKqKk8DGz2FPjmFg +z5WyYWiCG28oTmBDHXhN5i5X+pPXOlwSvUiGmrvZswewbA4qfBX8jLwqmH/5VaNA +iegS05MjTsYEtgAjogCAW3kv9ka2bOnw6r6GWBiKebE2JU8my+B0H07o9NJ561r7 +qfyrclF/610z5b6Jh/v6jbCj2ZCkDTCxyXu4z7IbMY2bPW09QfaW4bYlsfehcwJR +uDtxekFbS73mmo9nhVXPhG9s5I3wawEahPoXGOVnwsE7BAABCgBvBYJkf2S3CRD7 +/MgqAV5zMEcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmeL +ydr/KwuIg2juO15I6oucMhsgNCcuFLmwzmRjN7WPXxYhBNGmbhojsYLJmA94jPv8 +yCoBXnMwAACzwgwAsa09M/8lZf3EfRfcDzzwYKUqkKkeyOdTGYZEw4Wr9q3bW+Ih +l8EECzntzPkTObJjNfRjlB8VW+XGgSY4CoNVbihDb/LN/9K35qqaJgp0Vw1w9KC0 +NcmWqykn+b3mmWcbHnxE9uEnG4QhCXIM9/u+O13oeKoteXc+bSYa7eA6JJpO2cBx +q/ZqG1CHp5x8+0QC2kiZllsmkZqgqCleF9M70Al/tk3OdnodsST5c2bwPkThnYJa +zEMBhHv2YPGLhwj6j0N+I+HTqloEZxd7gTcFsIDJhaiBrRjQ9D5ePdpzNLPtemG7 +9vxUeVpHniQAgkXHZqCct0S788kbMJC0hAOYWD/2AvmeI254FJqrd2ORdWoMFK1r +aAzRLWetj3ts4dcU/6Y36/AjMhN+zqPlxDrd3hXWWadP9HQqgld8H3UG8cLDM7Xd +ZRBqr5v2zwH9dgJTg/bVysKsg2LWm0m1k6rbd6EQm6ow6tOrgzvG7bsTbgvsWeOj +lc55TrCONOK1+qpI +=peEs +-----END PGP SIGNATURE----- diff --git a/tests/testdata/compatibility/sig4_sig23.sig b/tests/testdata/compatibility/sig4_sig23.sig new file mode 100644 index 00000000..90d7282e --- /dev/null +++ b/tests/testdata/compatibility/sig4_sig23.sig @@ -0,0 +1,26 @@ +-----BEGIN PGP SIGNATURE----- + +wsE7BAABCgBvBYJkf2S3CRD7/MgqAV5zMEcUAAAAAAAeACBzYWx0QG5vdGF0aW9u +cy5zZXF1b2lhLXBncC5vcmeLydr/KwuIg2juO15I6oucMhsgNCcuFLmwzmRjN7WP +XxYhBNGmbhojsYLJmA94jPv8yCoBXnMwAACzwgwAsa09M/8lZf3EfRfcDzzwYKUq +kKkeyOdTGYZEw4Wr9q3bW+Ihl8EECzntzPkTObJjNfRjlB8VW+XGgSY4CoNVbihD +b/LN/9K35qqaJgp0Vw1w9KC0NcmWqykn+b3mmWcbHnxE9uEnG4QhCXIM9/u+O13o +eKoteXc+bSYa7eA6JJpO2cBxq/ZqG1CHp5x8+0QC2kiZllsmkZqgqCleF9M70Al/ +tk3OdnodsST5c2bwPkThnYJazEMBhHv2YPGLhwj6j0N+I+HTqloEZxd7gTcFsIDJ +haiBrRjQ9D5ePdpzNLPtemG79vxUeVpHniQAgkXHZqCct0S788kbMJC0hAOYWD/2 +AvmeI254FJqrd2ORdWoMFK1raAzRLWetj3ts4dcU/6Y36/AjMhN+zqPlxDrd3hXW +WadP9HQqgld8H3UG8cLDM7XdZRBqr5v2zwH9dgJTg/bVysKsg2LWm0m1k6rbd6EQ +m6ow6tOrgzvG7bsTbgvsWeOjlc55TrCONOK1+qpIwsE7FwABCgBvBYJkf2S3CRD7 +/MgqAV5zMEcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmeL +ydr/KwuIg2juO15I6oucMhsgNCcuFLmwzmRjN7WPXxYhBNGmbhojsYLJmA94jPv8 +yCoBXnMwAACzwgwAsa09M/8lZf3EfRfcDzzwYKUqkKkeyOdTGYZEw4Wr9q3bW+Ih +l8EECzntzPkTObJjNfRjlB8VW+XGgSY4CoNVbihDb/LN/9K35qqaJgp0Vw1w9KC0 +NcmWqykn+b3mmWcbHnxE9uEnG4QhCXIM9/u+O13oeKoteXc+bSYa7eA6JJpO2cBx +q/ZqG1CHp5x8+0QC2kiZllsmkZqgqCleF9M70Al/tk3OdnodsST5c2bwPkThnYJa +zEMBhHv2YPGLhwj6j0N+I+HTqloEZxd7gTcFsIDJhaiBrRjQ9D5ePdpzNLPtemG7 +9vxUeVpHniQAgkXHZqCct0S788kbMJC0hAOYWD/2AvmeI254FJqrd2ORdWoMFK1r +aAzRLWetj3ts4dcU/6Y36/AjMhN+zqPlxDrd3hXWWadP9HQqgld8H3UG8cLDM7Xd +ZRBqr5v2zwH9dgJTg/bVysKsg2LWm0m1k6rbd6EQm6ow6tOrgzvG7bsTbgvsWeOj +lc55TrCONOK1+qpI +=FIFU +-----END PGP SIGNATURE----- diff --git a/tests/testdata/compatibility/skesk_unknown_s2k_algo.msg b/tests/testdata/compatibility/skesk_unknown_s2k_algo.msg new file mode 100644 index 00000000..c359159a --- /dev/null +++ b/tests/testdata/compatibility/skesk_unknown_s2k_algo.msg @@ -0,0 +1,16 @@ +-----BEGIN PGP MESSAGE----- + +wcDMA3wvqk35PDeyAQv+PkvYwtAPmEyGugGzZ3FvqGzxQ9kVm0N2+VjJ0VBMoWpz +jE6UB6rXXnBbaCCeiXiTKGTNOueyXB09xZVUxa1Kub4yTA90d+NxU7YFhUvcEzt+ +LgP9oWe3MrKB+WOFA7z9RAwCgfvBzwYZ9AFO/v4UHQVrDL7KLLnglPtcXnrvMf7G +ecqcoHAbyj/Jn4ZQqL1/fVF3Dqkfrv+M307IJtfh/SebMxAnYNDi/5U9xnZo/Bvf +JVGa2UtxrvyMkIbZZuy82ZzkDK1HI+NHQhBlksS00AKA/vIwTHKNsdITE+ToY7Pi +jjRU92Sl1KyKdt8e00DTPoDRWxxUFSVMJB4eSP/39HBcAVGW5tHYkMGYXhwRoxPD +qbxWawGfrLxCNga0n5cM3Z1I4m8jel1Xj0RvjWptgHYGB64oWte9hfh3GHT7o3X6 +40zJnsCrp6BFyY+lp7DHTsyOGCh6qxA+jvcu0UBMn+mSEkWmyP318KEN2ohJZzWt +rWzU709sTOgZDI1qqMbLw1AECRcIYWFhYWFhYWFBQUFBYWFhYWFhYWFhYWFhYWFh +YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh +YdJMAcrv4d2mV7fSrRu3vd/jV/rXB0VFRibJEQ3XOY63w1YtQh1AWR5jV/Dbk2KX +bIfeH7+ymnjV/ARiARK0I3aO/utvgC8+U1wJv3b39w== +=74qf +-----END PGP MESSAGE----- diff --git a/tests/testdata/compatibility/skesk_unknown_version.msg b/tests/testdata/compatibility/skesk_unknown_version.msg new file mode 100644 index 00000000..490b1a91 --- /dev/null +++ b/tests/testdata/compatibility/skesk_unknown_version.msg @@ -0,0 +1,16 @@ +-----BEGIN PGP MESSAGE----- + +wcDMA3wvqk35PDeyAQv+PkvYwtAPmEyGugGzZ3FvqGzxQ9kVm0N2+VjJ0VBMoWpz +jE6UB6rXXnBbaCCeiXiTKGTNOueyXB09xZVUxa1Kub4yTA90d+NxU7YFhUvcEzt+ +LgP9oWe3MrKB+WOFA7z9RAwCgfvBzwYZ9AFO/v4UHQVrDL7KLLnglPtcXnrvMf7G +ecqcoHAbyj/Jn4ZQqL1/fVF3Dqkfrv+M307IJtfh/SebMxAnYNDi/5U9xnZo/Bvf +JVGa2UtxrvyMkIbZZuy82ZzkDK1HI+NHQhBlksS00AKA/vIwTHKNsdITE+ToY7Pi +jjRU92Sl1KyKdt8e00DTPoDRWxxUFSVMJB4eSP/39HBcAVGW5tHYkMGYXhwRoxPD +qbxWawGfrLxCNga0n5cM3Z1I4m8jel1Xj0RvjWptgHYGB64oWte9hfh3GHT7o3X6 +40zJnsCrp6BFyY+lp7DHTsyOGCh6qxA+jvcu0UBMn+mSEkWmyP318KEN2ohJZzWt +rWzU709sTOgZDI1qqMbLw00XCQMIMiFs6BH34GH/YWFhYWFhYWFhYWFhYWFhYWFh +YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYdJM +Acrv4d2mV7fSrRu3vd/jV/rXB0VFRibJEQ3XOY63w1YtQh1AWR5jV/Dbk2KXbIfe +H7+ymnjV/ARiARK0I3aO/utvgC8+U1wJv3b39w== +=e3i1 +-----END PGP MESSAGE----- diff --git a/tox.ini b/tox.ini index 0956986e..937511c8 100644 --- a/tox.ini +++ b/tox.ini @@ -27,7 +27,6 @@ passenv = deps = cryptography>=2.6 gpg==1.10.0 - pyasn1 six>=1.9.0 pytest pytest-cov