Files
PGPy-3_13_patch/tests/test_01_packetfields.py
Michael Greene 0ab3a67288 cleanup
[skip ci]
2017-02-16 20:36:00 -08:00

357 lines
14 KiB
Python

""" test field parsing
"""
import pytest
import itertools
from pgpy.constants import HashAlgorithm
from pgpy.constants import String2KeyType
from pgpy.constants import SymmetricKeyAlgorithm
from pgpy.packet.fields import String2Key
from pgpy.packet.types import Header
from pgpy.packet.subpackets import Signature
from pgpy.packet.subpackets import UserAttribute
from pgpy.packet.subpackets.types import Header as HeaderSP
from pgpy.packet.subpackets.types import Opaque as OpaqueSP
_trailer = b'\xde\xca\xff\xba\xdd'
_tag = bytearray(b'\xc2')
pkt_headers = [
# new format
# 1 byte length - 191
_tag + b'\xbf' + (b'\x00' * 191) + _trailer,
# 2 byte length - 192
_tag + b'\xc0\x00' + (b'\x00' * 192) + _trailer,
# 2 byte length - 8383
_tag + b'\xdf\xff' + (b'\x00' * 8383) + _trailer,
# 5 byte length - 8384
_tag + b'\xff\x00\x00 \xc0' + (b'\x00' * 8384) + _trailer,
# old format
# 1 byte length - 255
bytearray(b'\x88') + b'\xff' + (b'\x00' * 255) + _trailer,
# 2 byte length - 256
bytearray(b'\x89') + b'\x01\x00' + (b'\x00' * 256) + _trailer,
# 4 byte length - 65536
bytearray(b'\x8a') + b'\x00\x01\x00\x00' + (b'\x00' * 65536) + _trailer,
]
subpkt_headers = [
# 1 byte length - 191
bytearray(b'\xbf' + b'\x00' + (b'\x00' * 190)),
# 2 byte length - 192
bytearray(b'\xc0\x00' + b'\x00' + (b'\x00' * 191)),
# 2 byte length - 8383
bytearray(b'\xdf\xff' + b'\x00' + (b'\x00' * 8382)),
# 5 byte length - 8384
bytearray(b'\xff\x00\x00 \xc0' + b'\x00' + (b'\x00' * 0x8383)),
# 5 byte length - 65535
bytearray(b'\xff\x00\x00\xff\xff' + b'\x00' + (b'\x00' * 65534)),
]
class TestHeaders(object):
@pytest.mark.parametrize('pheader', pkt_headers)
def test_packet_header(self, pheader):
b = pheader[:]
h = Header()
h.parse(pheader)
assert h.tag == 0x02
assert h.length == len(pheader) - len(_trailer)
assert pheader[h.length:] == _trailer
assert len(h) == len(b) - len(pheader)
assert h.__bytes__() == b[:len(h)]
@pytest.mark.parametrize('spheader', subpkt_headers)
def test_subpacket_header(self, spheader):
h = HeaderSP()
h.parse(spheader)
assert 65537 > h.length > 1
assert len(h) == len(h.__bytes__())
_sspclasses = {
# 0x00: 'Opaque',
# 0x01: 'Opaque',
0x02: 'CreationTime',
0x03: 'SignatureExpirationTime',
0x04: 'ExportableCertification',
0x05: 'TrustSignature',
0x06: 'RegularExpression',
0x07: 'Revocable',
# 0x08: 'Opaque',
0x09: 'KeyExpirationTime',
# 0x0a: 'AdditionalDecryptionKey', ##TODO: parse this, then uncomment
0x0b: 'PreferredSymmetricAlgorithms',
0x0c: 'RevocationKey',
# 0x0d: 'Opaque',
# 0x0e: 'Opaque',
# 0x0f: 'Opaque',
0x10: 'Issuer',
# 0x11: 'Opaque',
0x12: 'Opaque', # reserved
# 0x13: 'Opaque',
0x14: 'NotationData',
0x15: 'PreferredHashAlgorithms',
0x16: 'PreferredCompressionAlgorithms',
0x17: 'KeyServerPreferences',
0x18: 'PreferredKeyServer',
0x19: 'PrimaryUserID',
0x1a: 'Policy',
0x1b: 'KeyFlags',
0x1c: 'SignersUserID',
0x1d: 'ReasonForRevocation',
0x1e: 'Features',
# 0x1f: 'Target', ##TODO: obtain one of these ##TODO: parse this, then uncomment
0x20: 'EmbeddedSignature',
# 0x64-0x6e: Private or Experimental
0x64: 'Opaque',
0x65: 'Opaque',
0x66: 'Opaque',
0x67: 'Opaque',
0x68: 'Opaque',
0x69: 'Opaque',
0x6a: 'Opaque',
0x6b: 'Opaque',
0x6c: 'Opaque',
0x6d: 'Opaque',
0x6e: 'Opaque',
}
_uaspclasses = {
0x01: 'Image'
}
_ssps = [
# 0x02 - creation time
b'\x05\x02?z\xf7\x13',
# 0x03 - expiration time
b'\x05\x03\x00\x12u\x00',
# 0x04 - exportable certification
b'\x02\x04\x00',
# 0x05
b'\x03\x05\x01x',
# 0x06
b'\x1d\x06<[^>]+[@.]liebenzell\\.org>$\x00',
# 0x07
b'\x02\x07\x00',
# 0x08
# 0x09
b'\x05\t\x01\xe13\x80',
# 0x0a
b'\x17\n\x00\x11M,\x9e,\xee~&\rK\xbd\x9b[\x1b`\xbcu\x0c\xefW\x06',
# 0x0b
b'\x05\x0b\x07\n\x03\x04',
# 0x0c
b'\x17\x0c\x80\x119\x06\xf8\xf6\x98d\x9e\xbePG\xd0\xba\x11\xed\xa7\xd0!<\xa1\x1b',
# 0x10
b"\t\x10\n'Z\xb6\xb4\xbc\xa5\xd7",
# 0x12
b'\x05\x12R/\xe2d',
# 0x14
b'\x87\x14\x80\x00\x00\x00\x00\x10\x00nsignotes@grep.be"http://www.grep.be/gpg/CF62318D5BBE'
b'D48F33ACD5431B0006256FB29164/0138DA92EDFFB27DD270F86DB475E207BAB58229.asc"',
# 0x15
b'\x03\x15\x03\x02',
# 0x16
b'\x03\x16\x02\x01',
# 0x17
b'\x02\x17\x80',
# 0x18
b'\x19\x18hkp://fakekey.server.tld',
# 0x19
b'\x02\x19\x01',
# 0x1a
b'\x15\x1ahttp://www.blaap.org',
# 0x1b
b'\x02\x1b#',
# 0x1c
b' \x1cSander Temme <sander@temme.net>',
# 0x1d
b'\x02\x1d\x00',
# 0x1e
b'\x02\x1e\x01',
# 0x20
b"\xc0] \x04\x19\x01\n\x00\x06\x05\x02S\x9a6\x06\x00\n\t\x10\x19q\xf7\xb8\x80g\xdd\x07\xd20"
b"\x07\xfd\x19\xbb\xea;6|\xdb1\xf3\xbc\xfbZ\x1d\xb6\xcfY\xe6&\xe9\xed\xf1O\xdc\x84\xdd\xe1"
b"\x88\xff\xb9\xba\x1a\xe9\x8d\x16K\xd2\xb4\xf49\x7f(\xc9\xe8/\xf6\x87\x0f\xef\xb7*\xf9'r{E"
b"\xf3\x07?\xcb\xffm\x87\x86&H\xee\xc4\xbc\xf1L\x177\x92\xdb\xf9I\x16Q\xf6\x9ei\xf56z\x0f\xff"
b"^\x92\x88Kh\xbd; \x86\xa5\xbaL\xa2\xda\x93\xae\x10\xd1Y\xa5\xa7\xb4)*\xf6\xa1,]\xd1\xe3\\"
b"\xc3l3\xecA\xec&\x145\xe1\xc4\xd0\x15y\xb2\xf8\x0c\x0e\xd3_[\x1f\x0fM\x98\xa8J\xb3\xd9?\xa4"
b"\xb3\x16\xee8\xad/\x07\xea\x7f\xad\x1a\x0f\xbe\x06\x94\xa51\xf6@\xae\xcdy\x92B\x1c\xd5\x04z"
b"\xbf\xe9\xbc\x9c\xac\x99W6\x81\xad\xe0\x81\xb4\x89n\xd0_\x1c\x92\xbe\xf6\x1cmn\xe92_\x86\xcf"
b"\xb0v\x1f\x9dk%\xbd<\x0c\x1e\x91\x0c\xec\\\xdc\x8cCu\xd8N\xf2\x82E\x00\xc8rnSY\x1b\xa0%\x13"
b"\xc0$Q+\xd3\xd0\xd8 \x0c\xe9\xafI5&\xe5\xc1!\xaf",
# 0x65
b'\x07eGPG\x00\x01\x01',
]
sig_subpkts = [bytearray(sp) + _trailer for sp in _ssps]
class TestSignatureSubPackets(object):
@pytest.mark.parametrize('sigsubpacket', sig_subpkts)
def test_load(self, sigsubpacket):
spb = sigsubpacket[:]
sp = Signature(spb)
assert spb == _trailer
assert len(sp) == len(sigsubpacket) - len(_trailer)
assert len(sp) == len(sp.__bytes__())
assert sp.__bytes__() == bytes(sigsubpacket[:-len(_trailer)])
if sp.header.typeid in _sspclasses:
assert sp.__class__.__name__ == _sspclasses[sp.header.typeid]
else:
assert isinstance(sp, OpaqueSP)
_uassps = [
# 0x01
b'\xc3\xfd\x01\x10\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xd8\xff'
b'\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00\x84\x00\xff\xff\xff'
b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'
b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'
b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\xff\xff\xff\xff'
b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'
b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'
b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\x11\x08\x00x'
b'\x00x\x03\x01\x11\x00\x02\x11\x01\x03\x11\x01\xff\xc4\x01\xa2\x00\x00\x01\x05\x01\x01\x01'
b'\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x10'
b'\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05\x04\x04\x00\x00\x01}\x01\x02\x03\x00\x04\x11\x05'
b'\x12!1A\x06\x13Qa\x07"q\x142\x81\x91\xa1\x08#B\xb1\xc1\x15R\xd1\xf0$3br\x82\t\n\x16\x17'
b'\x18\x19\x1a%&\'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz\x83\x84\x85\x86\x87\x88\x89\x8a'
b'\x92\x93\x94\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5'
b'\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9'
b'\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\x01'
b'\x00\x03\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05'
b'\x06\x07\x08\t\n\x0b\x11\x00\x02\x01\x02\x04\x04\x03\x04\x07\x05\x04\x04\x00\x01\x02w\x00'
b'\x01\x02\x03\x11\x04\x05!1\x06\x12AQ\x07aq\x13"2\x81\x08\x14B\x91\xa1\xb1\xc1\t#3R\xf0\x15'
b'br\xd1\n\x16$4\xe1%\xf1\x17\x18\x19\x1a&\'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz\x82'
b'\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6'
b'\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca'
b'\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf2\xf3\xf4\xf5'
b'\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x0c\x03\x01\x00\x02\x11\x03\x11\x00?\x00\x92\x80\n\x00('
b'\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n'
b'\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80'
b'\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02'
b'\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0'
b'\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x04\xc8\x1dH\xa0\x03'
b'#\xd4~t\x00\xb4\x00P\x02d\x0e\xa6\x80\x0c\x83\xd0\x8a\x00Z\x00:P\x02dz\x8f\xccP\x02\xd0'
b'\x01@\x05\x00\x14\x00P\x01@\x11cs\x1c\xfb\xd0\x03\xb6\x0fS@\r\x19V\xc7j\x00{\x1c\x0f~\xd4'
b'\x00\xc0\xb9\xe4\x9e\xb4\x00\xa5;\x8c\xd0\x02\xa1\xc8\xe7\xb5\x005\xb9`>\x9f\xce\x80\x1d'
b'\xb0z\x9a\x00i\x05\x0eA\xa0\t\x01\xc8\x07\xd6\x80\x16\x80\n\x00(\x00\xa0\x08\x81\x01\x89>'
b'\xff\x00\xce\x80\x1d\xbdh\x01\xbfy\xb3\xd8P\x00\xfdG\xd2\x80%\xa0\x06\xeeQ\xde\x80\x14\x10'
b'zP\x04m\xf7\x87\xe1\xfc\xe8\x01\xfb\xd6\x80\x18\xc7v\x00\xa0\x05q\xf2\x8fj\x00z\x9c\x80h'
b'\x01\x87\xe6\x7f\xa7\xf4\xa0\t(\x00\xa0\x08\x80\x05\x8e}\xff\x00\x9d\x00I\xb5}\x05\x00/N'
b'\x94\x01\x1b\x8e\x87\xf0\xa0\x07\x83\x91\x9a\x00B\xab\xd4\x8a\x00ju4\x00\x8d\xf7\x87\xe1'
b'\xfc\xe8\x02M\xab\xe8(\x00\x00\x0e\x82\x80\x14\xf21@\x11)\xdb\xb8\x1f\xf2h\x01\xc8:\x9fZ'
b'\x00}\x00\x14\x00\xc0\xa41=\xb9\xfdh\x01\xf4\x00P\x02\x11\x9e\r\x003k\x0e\x86\x80\x0c9\xeb'
b'\xd3\xfc\xfaP\x02\xa8 \x9c\xd0\x00T\x96\x07\xb7\x1f\xa5\x00>\x80\n\x00(\x02\'\x1f7\x1d\xe8'
b'\x02@01@\x0b@\x05\x00\x14\x00P\x01@\x05\x00\x14\x00P\x01@\x05\x00\x14\x00P\x01@\t\x81\x9c'
b'\xf7\xa0\x05\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02'
b'\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0'
b'\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00'
b'\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00('
b'\x00\xa0\x02\x80?\xff\xd9',
]
ua_subpkts = [bytearray(sp) + _trailer for sp in _uassps]
class TestUserAttributeSubPackets(object):
@pytest.mark.parametrize('uasubpacket', ua_subpkts)
def test_load(self, uasubpacket):
spb = uasubpacket[:]
sp = UserAttribute(spb)
assert spb == _trailer
assert len(sp) == len(uasubpacket) - len(_trailer)
assert len(sp) == len(sp.__bytes__())
assert sp.__bytes__() == uasubpacket[:-len(_trailer)]
if sp.header.typeid in _uaspclasses:
assert sp.__class__.__name__ == _uaspclasses[sp.header.typeid]
else:
assert isinstance(sp, OpaqueSP)
_s2k_parts = [
# usage byte is always \xff
b'\xff',
# symmetric cipher algorithm list
b'\x01\x02\x03\x04\x07\x08\x09\x0B\x0C\x0D',
# specifier
# b'\x00', (simple)
# b'\x01', (iterated)
# b'\x03', (salted)
# hash algorithm list
b'\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B',
]
_iv = b'\xDE\xAD\xBE\xEF\xDE\xAD\xBE\xEF'
_salt = b'\xC0\xDE\xC0\xDE\xC0\xDE\xC0\xDE'
_count = b'\x10' # expands from 0x10 to 2048
# simple S2Ks
sis2ks = [bytearray(i) + _iv for i in itertools.product(*(_s2k_parts[:2] + [b'\x00'] + _s2k_parts[2:]))]
# salted S2Ks
sas2ks = [bytearray(i) + _salt + _iv for i in itertools.product(*(_s2k_parts[:2] + [b'\x01'] + _s2k_parts[2:]))]
# iterated S2Ks
is2ks = [bytearray(i) + _salt + _count + _iv for i in itertools.product(*(_s2k_parts[:2] + [b'\x03'] + _s2k_parts[2:]))]
class TestString2Key(object):
@pytest.mark.parametrize('sis2k', sis2ks)
def test_simple_string2key(self, sis2k):
b = sis2k[:]
s = String2Key()
s.parse(sis2k)
assert len(sis2k) == 0
assert len(s) == len(b)
assert s.__bytes__() == b
assert bool(s)
assert s.halg in HashAlgorithm
assert s.encalg in SymmetricKeyAlgorithm
assert s.specifier == String2KeyType.Simple
assert s.iv == _iv
@pytest.mark.parametrize('sas2k', sas2ks)
def test_salted_string2key(self, sas2k):
b = sas2k[:]
s = String2Key()
s.parse(sas2k)
assert len(sas2k) == 0
assert len(s) == len(b)
assert s.__bytes__() == b
assert bool(s)
assert s.halg in HashAlgorithm
assert s.encalg in SymmetricKeyAlgorithm
assert s.specifier == String2KeyType.Salted
assert s.salt == _salt
assert s.iv == _iv
@pytest.mark.parametrize('is2k', is2ks)
def test_iterated_string2key(self, is2k):
b = is2k[:]
s = String2Key()
s.parse(is2k)
assert len(is2k) == 0
assert len(s) == len(b)
assert s.__bytes__() == b
assert bool(s)
assert s.halg in HashAlgorithm
assert s.encalg in SymmetricKeyAlgorithm
assert s.specifier == String2KeyType.Iterated
assert s.salt == _salt
assert s.count == 2048
assert s.iv == _iv