Esempio n. 1
0
 def test_parse_wrong_contents(self):
     notsigtext = _read(
         'tests/testdata/blocks/message.compressed.asc').replace(
             'MESSAGE', 'SIGNATURE')
     sig = PGPSignature()
     with pytest.raises(ValueError):
         sig.parse(notsigtext)
Esempio n. 2
0
    def test_select_pgpsignature(self, keyring):
        sig = PGPSignature()
        with open('tests/testdata/signatures/debian-sid.sig.asc', 'r') as sigf:
            sig.parse(sigf.read())

        with keyring.key(sig) as sigkey:
            assert sigkey.fingerprint.keyid == sig.signer
    def test_select_pgpsignature(self, keyring):
        sig = PGPSignature()
        with open('tests/testdata/signatures/debian-sid.sig.asc', 'r') as sigf:
            sig.parse(sigf.read())

        with keyring.key(sig) as sigkey:
            assert sigkey.fingerprint.keyid == sig.signer
Esempio n. 4
0
    def test_verify_wrongkey(self, rsa_pub):
        wrongkey, _ = PGPKey.from_file(
            'tests/testdata/signatures/aptapproval-test.key.asc')
        sig = PGPSignature.from_file(
            'tests/testdata/signatures/debian-sid.sig.asc')

        with pytest.raises(PGPError):
            wrongkey.verify(_read('tests/testdata/signatures/debian-sid.subj'),
                            sig)
Esempio n. 5
0
 def verify(self, data, signature):
     sig = PGPSignature(signature) \
         if isinstance(signature, str) else signature
     keyhandle = sig.signer
     key = self._get_key_from_keyhandle(keyhandle)
     skey = key if key.is_public is False else key.pubkey
     ver = skey.verify(data, signature)
     good = next(ver.good_signatures)
     return good.by
Esempio n. 6
0
def verify(profile, data, signature):
    sig = PGPSignature(signature) \
        if isinstance(signature, str) else signature
    keyhandle = sig.signer
    logger.debug('keyhandle %s', keyhandle)
    addr = _get_addr_from_keyhandle(profile, keyhandle)
    seckey = _get_seckey_from_addr(profile, addr)
    ver = seckey.verify(data, signature)
    good = next(ver.good_signatures)
    return good.by
Esempio n. 7
0
def verify() -> None:
    # signature verification requested
    commit_data = sys.stdin.read()
    if len(args) != 5:
        raise Exception(
            "Unexpected number of parameters encountered: {}".format(
                len(args)))
    if not args[0] == "--keyid-format=long":
        raise Exception(
            "Unexpected parameter encountered in args[0]: {}".format(args[0]))
    if not args[1] == "--status-fd=1":
        raise Exception(
            "Unexpected parameter encountered in args[1]: {}".format(args[1]))
    if not args[2] == "--verify":
        raise Exception(
            "Unexpected parameter encountered in args[2]: {}".format(args[2]))
    filename = args[3]
    if not args[4] == "-":
        raise Exception(
            "Unexpected parameter encountered in args[4]: {}".format(args[2]))

    signature = PGPSignature.from_file(filename)

    key = API.combined_keystore.get_key(signature.signer)
    if key is not None:
        if key.verify(commit_data, signature):
            trusted_uids, untrusted_uids = deduplicate_uids(
                verify_uid_certifications(key))

            trusted_uids = strip_pseudo_uid(trusted_uids)
            untrusted_uids = strip_pseudo_uid(untrusted_uids)

            status_to_user(signature, key, trusted_uids, untrusted_uids)
            status_to_caller(signature, key, trusted_uids)
        else:
            raise Exception("Invalid signature")
    else:
        raise NotImplementedError("Key not found")
Esempio n. 8
0
 def test_parse_wrong_magic(self):
     sigtext = _read('tests/testdata/blocks/signature.expired.asc').replace('SIGNATURE', 'SIGANTURE')
     sig = PGPSignature()
     with pytest.raises(ValueError):
         sig.parse(sigtext)
Esempio n. 9
0
 def test_parse_wrong_magic(self):
     sigtext = _read('tests/testdata/blocks/signature.expired.asc').replace(
         'SIGNATURE', 'SIGANTURE')
     sig = PGPSignature()
     with pytest.raises(ValueError):
         sig.parse(sigtext)
Esempio n. 10
0
 def test_or_typeerror(self):
     with pytest.raises(TypeError):
         PGPSignature() | 12
Esempio n. 11
0
 def test_gpg_ed25519_verify(self, abe):
     # test verification of Ed25519 signature generated by GnuPG
     pubkey, _ = PGPKey.from_file('tests/testdata/keys/ecc.2.pub.asc')
     sig = PGPSignature.from_file('tests/testdata/signatures/ecc.2.sig.asc')
     assert pubkey.verify("This is a test signature message", sig)
Esempio n. 12
0
class TestPGPKey(object):
    params = {
        'pub': [
            PGPKey.from_file(f)[0]
            for f in sorted(glob.glob('tests/testdata/keys/*.pub.asc'))
        ],
        'sec': [
            PGPKey.from_file(f)[0]
            for f in sorted(glob.glob('tests/testdata/keys/*.sec.asc'))
        ],
        'enc': [
            PGPKey.from_file(f)[0]
            for f in sorted(glob.glob('tests/testdata/keys/*.enc.asc'))
        ],
        'sigkey': [
            PGPKey.from_file(f)[0]
            for f in sorted(glob.glob('tests/testdata/signatures/*.key.asc'))
        ],
        'sigsig': [
            PGPSignature.from_file(f)
            for f in sorted(glob.glob('tests/testdata/signatures/*.sig.asc'))
        ],
        'sigsubj':
        sorted(glob.glob('tests/testdata/signatures/*.subj')),
        'key_alg':
        key_algs,
    }
    ids = {
        'test_protect': [
            '-'.join(os.path.basename(f).split('.')[:-2])
            for f in sorted(glob.glob('tests/testdata/keys/*.sec.asc'))
        ],
        'test_encrypt_message': [
            '-'.join(os.path.basename(f).split('.')[:-2])
            for f in sorted(glob.glob('tests/testdata/keys/*.pub.asc'))
        ],
        'test_decrypt_encmessage': [
            '-'.join(os.path.basename(f).split('.')[:-2])
            for f in sorted(glob.glob('tests/testdata/keys/*.sec.asc'))
        ],
        'test_verify_detached': [
            os.path.basename(f).replace('.', '_')
            for f in sorted(glob.glob('tests/testdata/signatures/*.key.asc'))
        ],
        'test_new_key': [str(ka).split('.')[-1] for ka in key_algs],
        'test_new_subkey': [str(ka).split('.')[-1] for ka in key_algs],
        'test_pub_from_sec': [str(ka).split('.')[-1] for ka in key_algs],
        'test_gpg_verify_new_key': [str(ka).split('.')[-1] for ka in key_algs],
        'test_verify_invalid_sig': [str(ka).split('.')[-1] for ka in key_algs],
    }
    string_sigs = dict()
    timestamp_sigs = dict()
    standalone_sigs = dict()
    gen_keys = dict()
    encmessage = []

    @contextmanager
    def assert_warnings(self):
        with catch_warnings(record=True) as w:
            try:
                yield

            finally:
                for warning in w:
                    try:
                        assert warning.filename == __file__

                    except AssertionError as e:
                        e.args += (warning.message, )
                        raise

    def test_protect(self, sec):
        # if sec.key_algorithm == PubKeyAlgorithm.ECDSA:
        #     pytest.skip("Cannot properly encrypt ECDSA keys yet")

        assert sec.is_protected is False

        # copy sec so we have a comparison point
        sec2 = copy.deepcopy(sec)
        # ensure that the key material values are the same
        assert _compare_keys(sec, sec2)

        sec2.protect('There Are Many Like It, But This Key Is Mine',
                     SymmetricKeyAlgorithm.AES256, HashAlgorithm.SHA256)

        assert sec2.is_protected
        assert sec2.is_unlocked is False
        # ensure that sec2 is now
        assert _compare_keys(sec, sec2) is False

        assert sec2._key.keymaterial.__bytes__()[sec2._key.keymaterial.publen(
        ):] not in sec._key.keymaterial.__bytes__()

        # unlock with the correct passphrase and compare the keys
        with sec2.unlock(
                'There Are Many Like It, But This Key Is Mine') as _unlocked:
            assert _unlocked.is_unlocked
            assert _compare_keys(sec, sec2)

    def test_unlock(self, enc, sec):
        assert enc.is_protected
        assert enc.is_unlocked is False
        assert sec.is_protected is False

        # unlock with the correct passphrase
        with enc.unlock('QwertyUiop') as _unlocked, self.assert_warnings():
            assert _unlocked is enc
            assert enc.is_unlocked

    def test_change_passphrase(self, enc):
        enc2 = copy.deepcopy(enc)

        assert enc.is_protected
        assert enc2.is_protected
        assert enc.is_unlocked is False
        assert enc2.is_unlocked is False

        assert enc._key.keymaterial.encbytes == enc2._key.keymaterial.encbytes

        # change the passphrase on enc2
        with enc.unlock('QwertyUiop') as e1u, enc2.unlock(
                'QwertyUiop') as e2u, self.assert_warnings():
            assert _compare_keys(e1u, e2u)
            enc2.protect('AsdfGhjkl', enc2._key.keymaterial.s2k.encalg,
                         enc2._key.keymaterial.s2k.halg)

        assert enc._key.keymaterial.encbytes != enc2._key.keymaterial.encbytes

        # unlock again and verify that we still have the same key hiding in there
        with enc.unlock('QwertyUiop') as e1u, enc2.unlock(
                'AsdfGhjkl') as e2u, self.assert_warnings():
            assert _compare_keys(e1u, e2u)

    def test_verify_detached(self, sigkey, sigsig, sigsubj):
        assert sigkey.verify(_read(sigsubj), sigsig)

    def test_sign_string(self, sec, string, write_clean, gpg_import,
                         gpg_verify):
        with self.assert_warnings():
            # add all of the subpackets we should be allowed to
            sig = sec.sign(
                string,
                user=sec.userids[0].name,
                expires=timedelta(seconds=1),
                revocable=False,
                notation={
                    'Testing':
                    'This signature was generated during unit testing'
                },
                policy_uri='about:blank')

        # wait a bit if sig is not yet expired
        assert sig.type == SignatureType.BinaryDocument
        assert sig.notation == {
            'Testing': 'This signature was generated during unit testing'
        }
        assert sig.revocable is False
        assert sig.policy_uri == 'about:blank'
        # assert sig.sig.signer_uid == "{:s}".format(sec.userids[0])
        assert next(iter(sig._signature.subpackets['SignersUserID'])
                    ).userid == "{:s}".format(sec.userids[0])
        if not sig.is_expired:
            time.sleep((sig.expires_at - datetime.utcnow()).total_seconds())
        assert sig.is_expired

        # verify with GnuPG
        if sig.key_algorithm not in {PubKeyAlgorithm.ECDSA}:
            # TODO: cannot test ECDSA against GnuPG as there isn't an easy way of installing v2.1 yet on CI
            with write_clean('tests/testdata/string', 'w', string), \
                    write_clean('tests/testdata/string.asc', 'w', str(sig)), \
                    gpg_import('./pubtest.asc'):
                assert gpg_verify('./string', './string.asc', keyid=sig.signer)

        self.string_sigs[sec.fingerprint.keyid] = sig

    def test_verify_string(self, pub, string):
        sig = self.string_sigs.pop(pub.fingerprint.keyid)
        with self.assert_warnings():
            sv = pub.verify(string, signature=sig)

        assert sv
        assert len(sv) == 1

    def test_sign_ctmessage(self, sec, ctmessage, write_clean, gpg_import,
                            gpg_verify):
        expire_at = datetime.utcnow() + timedelta(days=1)
        assert isinstance(expire_at, datetime)

        with self.assert_warnings():
            sig = sec.sign(ctmessage, expires=expire_at)

        assert sig.type == SignatureType.CanonicalDocument
        assert sig.revocable
        assert sig.is_expired is False

        ctmessage |= sig

        # verify with GnuPG
        if sig.key_algorithm not in {PubKeyAlgorithm.ECDSA}:
            # TODO: cannot test ECDSA against GnuPG as there isn't an easy way of installing v2.1 yet on CI
            with write_clean('tests/testdata/ctmessage.asc', 'w',
                             str(ctmessage)), gpg_import('./pubtest.asc'):
                assert gpg_verify('./ctmessage.asc', keyid=sig.signer)

    def test_verify_ctmessage(self, pub, ctmessage):
        with self.assert_warnings():
            sv = pub.verify(ctmessage)

        assert sv
        assert len(sv) > 0

    def test_sign_message(self, sec, message):
        with self.assert_warnings():
            sig = sec.sign(message)

        assert sig.type == SignatureType.BinaryDocument
        assert sig.revocable
        assert sig.is_expired is False

        message |= sig

    def test_verify_message(self, pub, message):
        with self.assert_warnings():
            sv = pub.verify(message)

        assert sv
        assert len(sv) > 0

    def test_gpg_verify_message(self, message, write_clean, gpg_import,
                                gpg_verify):
        # verify with GnuPG
        with write_clean('tests/testdata/message.asc', 'w',
                         str(message)), gpg_import('./pubtest.asc'):
            assert gpg_verify('./message.asc')

    def test_verify_invalid_sig(self, string, key_alg):
        # generate a keypair
        u = PGPUID.new('asdf')
        k = PGPKey.new(key_alg, key_alg_size[key_alg])
        k.add_uid(u,
                  usage={KeyFlags.Certify, KeyFlags.Sign},
                  hashes=[HashAlgorithm.SHA1])

        # sign string with extra characters (this means k.pubkey.verify(string) will return false
        sig = k.sign(string + 'asdf')

        assert not k.pubkey.verify(string, sig)

    def test_encrypt_message(self, pub, message, sessionkey):
        if pub.key_algorithm not in {
                PubKeyAlgorithm.RSAEncryptOrSign, PubKeyAlgorithm.ECDSA
        }:
            pytest.skip(
                'Asymmetric encryption only implemented for RSA/ECDSA currently'
            )
            return

        if len(self.encmessage) == 1:
            message = self.encmessage.pop(0)

        with self.assert_warnings():
            enc = pub.encrypt(message,
                              sessionkey=sessionkey,
                              cipher=SymmetricKeyAlgorithm.AES128)
            self.encmessage.append(enc)

    def test_decrypt_encmessage(self, sec, message):
        if sec.key_algorithm not in {
                PubKeyAlgorithm.RSAEncryptOrSign, PubKeyAlgorithm.ECDSA
        }:
            pytest.skip(
                'Asymmetric encryption only implemented for RSA and ECDH currently'
            )
            return

        encmessage = self.encmessage[0]

        with self.assert_warnings():
            decmsg = sec.decrypt(encmessage)

        assert decmsg.message == message.message

    def test_gpg_decrypt_encmessage(self, write_clean, gpg_import,
                                    gpg_decrypt):
        emsg = self.encmessage.pop(0)
        with write_clean('tests/testdata/aemsg.asc', 'w', str(emsg)):
            # decrypt using RSA
            with gpg_import('./sectest.asc'):
                assert gpg_decrypt('./aemsg.asc', keyid='EEE097A017B979CA')

            # decrypt using ECDH
            if gpg_ver >= '2.1':
                with gpg_import('./keys/ecc.1.sec.asc'):
                    assert gpg_decrypt('./aemsg.asc', keyid='D01055FBCADD268E')

    def test_encrypt_message_select_uid(self):
        # generate a temporary key with two UIDs, then encrypt a message
        u1 = PGPUID.new('UID One')
        u2 = PGPUID.new('UID Two')
        k = PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 512)

        flags = {
            KeyFlags.Certify, KeyFlags.Sign, KeyFlags.EncryptCommunications,
            KeyFlags.EncryptStorage
        }

        k.add_uid(u1,
                  usage=flags,
                  hashes=[HashAlgorithm.SHA1],
                  ciphers=[SymmetricKeyAlgorithm.AES128])
        k.add_uid(u2,
                  usage=flags,
                  hashes=[HashAlgorithm.SHA1],
                  ciphers=[SymmetricKeyAlgorithm.Camellia128])

        emsg = k.pubkey.encrypt(
            PGPMessage.new('This message is about to be encrypted'),
            user='******')

        # assert that it was encrypted with Camellia128 and that we can decrypt it normally
        assert emsg._sessionkeys[0].decrypt_sk(
            k._key)[0] == SymmetricKeyAlgorithm.Camellia128
        assert k.decrypt(
            emsg).message == 'This message is about to be encrypted'

    def test_sign_timestamp(self, sec):
        with self.assert_warnings():
            sig = sec.sign(None)

        assert sig.type == SignatureType.Timestamp
        self.timestamp_sigs[sec.fingerprint.keyid] = sig

    def test_verify_timestamp(self, pub):
        sig = self.timestamp_sigs.pop(pub.fingerprint.keyid)
        with self.assert_warnings():
            sv = pub.verify(None, sig)

        assert sv
        assert len(sv) > 0

    def test_sign_standalone(self, sec):
        with self.assert_warnings():
            sig = sec.sign(None, notation={"cheese status": "standing alone"})

        assert sig.type == SignatureType.Standalone
        assert sig.notation == {"cheese status": "standing alone"}
        self.standalone_sigs[sec.fingerprint.keyid] = sig

    def test_verify_standalone(self, pub):
        sig = self.standalone_sigs.pop(pub.fingerprint.keyid)
        with self.assert_warnings():
            sv = pub.verify(None, sig)

        assert sv
        assert len(sv) > 0

    def test_add_userid(self, userid, targette_sec):
        # add userid to targette_sec
        expire_in = datetime.utcnow() + timedelta(days=2)
        with self.assert_warnings():
            # add all of the subpackets that only work on self-certifications
            targette_sec.add_uid(userid,
                                 usage=[KeyFlags.Certify, KeyFlags.Sign],
                                 ciphers=[
                                     SymmetricKeyAlgorithm.AES256,
                                     SymmetricKeyAlgorithm.Camellia256
                                 ],
                                 hashes=[HashAlgorithm.SHA384],
                                 compression=[CompressionAlgorithm.ZLIB],
                                 key_expiration=expire_in,
                                 keyserver_flags=0x80,
                                 keyserver='about:none',
                                 primary=False)

        sig = userid.selfsig

        assert sig.type == SignatureType.Positive_Cert
        assert sig.cipherprefs == [
            SymmetricKeyAlgorithm.AES256, SymmetricKeyAlgorithm.Camellia256
        ]
        assert sig.hashprefs == [HashAlgorithm.SHA384]
        assert sig.compprefs == [CompressionAlgorithm.ZLIB]
        assert sig.features == {Features.ModificationDetection}
        assert sig.key_expiration == expire_in - targette_sec.created
        assert sig.keyserver == 'about:none'
        assert sig.keyserverprefs == [KeyServerPreferences.NoModify]

        assert userid.is_primary is False

    def test_remove_userid(self, targette_sec):
        # create a temporary userid, add it, and then remove it
        tempuid = PGPUID.new('Temporary Youx\'seur')
        targette_sec.add_uid(tempuid)

        assert tempuid in targette_sec

        targette_sec.del_uid('Temporary Youx\'seur')
        assert tempuid not in targette_sec

    def test_certify_userid(self, sec, userid):
        with self.assert_warnings():
            # add all of the subpackets that only work on (non-self) certifications
            sig = sec.certify(userid,
                              SignatureType.Casual_Cert,
                              usage=KeyFlags.Authentication,
                              exportable=True,
                              trust=(1, 60),
                              regex=r'.*')

        assert sig.type == SignatureType.Casual_Cert
        assert sig.key_flags == {KeyFlags.Authentication}
        assert sig.exportable
        # assert sig.trust_level == 1
        # assert sig.trust_amount == 60
        # assert sig.regex == r'.*'

        assert {sec.fingerprint.keyid} | set(sec.subkeys) & userid.signers

        userid |= sig

    def test_verify_userid(self, pub, userid):
        # with PGPy
        with self.assert_warnings():
            sv = pub.verify(userid)

        assert sv
        assert len(sv) > 0

    def test_add_photo(self, userphoto, targette_sec):
        with self.assert_warnings():
            targette_sec.add_uid(userphoto)

    def test_certify_photo(self, sec, userphoto):
        with self.assert_warnings():
            userphoto |= sec.certify(userphoto)

    def test_revoke_certification(self, sec, userphoto):
        # revoke the certifications of userphoto
        with self.assert_warnings():
            revsig = sec.revoke(userphoto)

        assert revsig.type == SignatureType.CertRevocation

        userphoto |= revsig

    def test_certify_key(self, sec, targette_sec):
        # let's add an 0x1f signature with notation
        # GnuPG does not like these, so we'll mark it as non-exportable
        with self.assert_warnings():
            sig = sec.certify(targette_sec,
                              exportable=False,
                              notation={
                                  'Notice': 'This key has been frobbed!',
                                  'Binary': bytearray(b'\xc0\x01\xd0\x0d')
                              })

        assert sig.type == SignatureType.DirectlyOnKey
        assert sig.exportable is False
        assert sig.notation == {
            'Notice': 'This key has been frobbed!',
            'Binary': bytearray(b'\xc0\x01\xd0\x0d')
        }

        targette_sec |= sig

    def test_self_certify_key(self, targette_sec):
        # let's add an 0x1f signature with notation
        with self.assert_warnings():
            sig = targette_sec.certify(
                targette_sec,
                notation={'Notice': 'This key has been self-frobbed!'})

        assert sig.type == SignatureType.DirectlyOnKey
        assert sig.notation == {'Notice': 'This key has been self-frobbed!'}

        targette_sec |= sig

    def test_add_revocation_key(self, sec, targette_sec):
        targette_sec |= targette_sec.revoker(sec)

    def test_verify_key(self, pub, targette_sec):
        with self.assert_warnings():
            sv = pub.verify(targette_sec)
            assert len(list(sv.good_signatures)) > 0
            assert sv

    def test_new_key(self, key_alg):
        # create a key and a user id and add the UID to the key
        uid = PGPUID.new('Hugo Gernsback', 'Science Fiction Plus',
                         '*****@*****.**')
        key = PGPKey.new(key_alg, key_alg_size[key_alg])
        key.add_uid(uid, hashes=[HashAlgorithm.SHA224])

        # self-verify the key
        assert key.verify(key)

        self.gen_keys[key_alg] = key

    def test_new_subkey(self, key_alg):
        key = self.gen_keys[key_alg]
        subkey = PGPKey.new(subkey_alg[key_alg],
                            key_alg_size[subkey_alg[key_alg]])

        assert subkey._key
        assert not isinstance(subkey._key, PrivSubKeyV4)

        # now add the subkey to key and then verify it
        key.add_subkey(subkey, usage={KeyFlags.EncryptCommunications})

        # subkey should be a PrivSubKeyV4 now, not a PrivKeyV4
        assert isinstance(subkey._key, PrivSubKeyV4)

        # self-verify
        sv = self.gen_keys[key_alg].verify(self.gen_keys[key_alg])

        assert sv
        assert subkey in sv

    def test_pub_from_sec(self, key_alg):
        priv = self.gen_keys[key_alg]

        pub = priv.pubkey

        assert pub.fingerprint == priv.fingerprint
        assert len(pub._key) == len(pub._key.__bytes__())
        for skid, subkey in priv.subkeys.items():
            assert skid in pub.subkeys
            assert pub.subkeys[skid].is_public
            assert len(subkey._key) == len(subkey._key.__bytes__())

    def test_gpg_verify_new_key(self, key_alg, write_clean, gpg_import,
                                gpg_check_sigs):
        if gpg_ver < '2.1' and key_alg in {
                PubKeyAlgorithm.ECDSA, PubKeyAlgorithm.ECDH
        }:
            pytest.skip("GnuPG version in use cannot import/verify ")

        # with GnuPG
        key = self.gen_keys[key_alg]
        with write_clean('tests/testdata/genkey.asc', 'w', str(key)), \
                gpg_import('./genkey.asc') as kio:

            assert 'invalid self-signature' not in kio
            assert gpg_check_sigs(key.fingerprint.keyid,
                                  *[skid for skid in key._children.keys()])

    def test_gpg_verify_key(self, targette_sec, write_clean, gpg_import,
                            gpg_check_sigs):
        # with GnuPG
        with write_clean('tests/testdata/targette.sec.asc', 'w', str(targette_sec)), \
                gpg_import('./pubtest.asc', './targette.sec.asc') as kio:
            assert 'invalid self-signature' not in kio
            assert gpg_check_sigs(targette_sec.fingerprint.keyid)

    def test_revoke_key(self, sec, pub, write_clean, gpg_import,
                        gpg_check_sigs):
        with self.assert_warnings():
            rsig = sec.revoke(pub,
                              sigtype=SignatureType.KeyRevocation,
                              reason=RevocationReason.Retired,
                              comment="But you're so oooold")
            assert 'ReasonForRevocation' in rsig._signature.subpackets
            pub |= rsig

            # verify with PGPy
            # assert pub.verify(pub)

        # verify with GPG
        kfp = '{:s}.asc'.format(pub.fingerprint.shortid)
        with write_clean(os.path.join('tests', 'testdata', kfp), 'w', str(kfp)), \
                gpg_import(os.path.join('.', kfp)) as kio:
            assert 'invalid self-signature' not in kio

        # and remove it, for good measure
        pub._signatures.remove(rsig)
        assert rsig not in pub

    def test_revoke_key_with_revoker(self):
        pytest.skip("not implemented yet")

    def test_revoke_subkey(self, sec, pub, write_clean, gpg_import,
                           gpg_check_sigs):
        if sec.key_algorithm == PubKeyAlgorithm.ECDSA:
            pytest.skip(
                "ECDH not implemented yet which causes this test to fail")

        subkey = next(iter(pub.subkeys.values()))
        with self.assert_warnings():
            # revoke the first subkey
            rsig = sec.revoke(subkey, sigtype=SignatureType.SubkeyRevocation)
            assert 'ReasonForRevocation' in rsig._signature.subpackets
            subkey |= rsig

            # verify with PGPy
            assert pub.verify(subkey)
            sv = pub.verify(pub)
            assert sv
            assert rsig in iter(s.signature for s in sv.good_signatures)

        # verify with GnuPG
        kfp = '{:s}.asc'.format(pub.fingerprint.shortid)
        with write_clean(os.path.join('tests', 'testdata', kfp), 'w', str(kfp)), \
                gpg_import(os.path.join('.', kfp)) as kio:
            assert 'invalid self-signature' not in kio

        # and remove it, for good measure
        subkey._signatures.remove(rsig)
        assert rsig not in subkey
Esempio n. 13
0
    def test_or_typeerror(self):
        sig = PGPSignature()

        with pytest.raises(TypeError):
            sig |= None
Esempio n. 14
0
    def test_verify_wrongkey(self, rsa_pub):
        wrongkey, _ = PGPKey.from_file('tests/testdata/signatures/aptapproval-test.key.asc')
        sig = PGPSignature.from_file('tests/testdata/signatures/debian-sid.sig.asc')

        with pytest.raises(PGPError):
            wrongkey.verify(_read('tests/testdata/signatures/debian-sid.subj'), sig)
Esempio n. 15
0
def sig():
    return PGPSignature.from_file('tests/testdata/blocks/rsasignature.asc')
Esempio n. 16
0
def sig():
    return PGPSignature.from_file('tests/testdata/blocks/rsasignature.asc')
def patched_pgpy_certify(self,
                         subject,
                         level=SignatureType.Generic_Cert,
                         **prefs):
    """
    Sign a key or a user id within a key.

    :param subject: The user id or key to be certified.
    :type subject: :py:obj:`PGPKey`, :py:obj:`PGPUID`
    :param level: :py:obj:`~constants.SignatureType.Generic_Cert`, :py:obj:`~constants.SignatureType.Persona_Cert`,
                  :py:obj:`~constants.SignatureType.Casual_Cert`, or :py:obj:`~constants.SignatureType.Positive_Cert`.
                  Only used if subject is a :py:obj:`PGPUID`; otherwise, it is ignored.
    :raises: :py:exc:`~pgpy.errors.PGPError` if the key is passphrase-protected and has not been unlocked
    :raises: :py:exc:`~pgpy.errors.PGPError` if the key is public
    :returns: :py:obj:`PGPSignature`

    In addition to the optional keyword arguments accepted by :py:meth:`PGPKey.sign`, the following optional
    keyword arguments can be used with :py:meth:`PGPKey.certify`.

    These optional keywords only make sense, and thus only have an effect, when self-signing a key or User ID:

    :keyword usage: A ``set`` of key usage flags, as :py:obj:`~constants.KeyFlags`.
                    This keyword is ignored for non-self-certifications.
    :type usage: ``set``
    :keyword ciphers: A list of preferred symmetric ciphers, as :py:obj:`~constants.SymmetricKeyAlgorithm`.
                      This keyword is ignored for non-self-certifications.
    :type ciphers: ``list``
    :keyword hashes: A list of preferred hash algorithms, as :py:obj:`~constants.HashAlgorithm`.
                     This keyword is ignored for non-self-certifications.
    :type hashes: ``list``
    :keyword compression: A list of preferred compression algorithms, as :py:obj:`~constants.CompressionAlgorithm`.
                          This keyword is ignored for non-self-certifications.
    :type compression: ``list``
    :keyword key_expiration: Specify a key expiration date for when this key should expire, or a
                          :py:obj:`~datetime.timedelta` of how long after the key was created it should expire.
                          This keyword is ignored for non-self-certifications.
    :type key_expiration: :py:obj:`datetime.datetime`, :py:obj:`datetime.timedelta`
    :keyword keyserver: Specify the URI of the preferred key server of the user.
                        This keyword is ignored for non-self-certifications.
    :type keyserver: ``str``, ``unicode``, ``bytes``
    :keyword primary: Whether or not to consider the certified User ID as the primary one.
                      This keyword is ignored for non-self-certifications, and any certifications directly on keys.
    :type primary: ``bool``

    These optional keywords only make sense, and thus only have an effect, when signing another key or User ID:

    :keyword trust: Specify the level and amount of trust to assert when certifying a public key. Should be a tuple
                    of two ``int`` s, specifying the trust level and trust amount. See
                    `RFC 4880 Section 5.2.3.13. Trust Signature <https://tools.ietf.org/html/rfc4880#section-5.2.3.13>`_
                    for more on what these values mean.
    :type trust: ``tuple`` of two ``int`` s
    :keyword regex: Specify a regular expression to constrain the specified trust signature in the resulting signature.
                    Symbolically signifies that the specified trust signature only applies to User IDs which match
                    this regular expression.
                    This is meaningless without also specifying trust level and amount.
    :type regex: ``str``
    """
    hash_algo = prefs.pop('hash', None)
    sig_type = level
    if isinstance(subject, PGPKey):
        sig_type = SignatureType.DirectlyOnKey

    created = prefs.pop('created', None)
    sig = PGPSignature.new(sig_type,
                           self.key_algorithm,
                           hash_algo,
                           self.fingerprint.keyid,
                           created=created)

    # signature options that only make sense in certifications
    usage = prefs.pop('usage', None)
    exportable = prefs.pop('exportable', None)

    if usage is not None:
        sig._signature.subpackets.addnew('KeyFlags', hashed=True, flags=usage)

    if exportable is not None:
        sig._signature.subpackets.addnew('ExportableCertification',
                                         hashed=True,
                                         bflag=exportable)

    keyfp = self.fingerprint
    if isinstance(subject, PGPKey):
        keyfp = subject.fingerprint
    if isinstance(subject, PGPUID) and subject._parent is not None:
        keyfp = subject._parent.fingerprint

    if keyfp == self.fingerprint:
        # signature options that only make sense in self-certifications
        cipher_prefs = prefs.pop('ciphers', None)
        hash_prefs = prefs.pop('hashes', None)
        compression_prefs = prefs.pop('compression', None)
        key_expires = prefs.pop('key_expiration', None)
        keyserver_flags = prefs.pop('keyserver_flags', None)
        keyserver = prefs.pop('keyserver', None)
        primary_uid = prefs.pop('primary', None)

        if key_expires is not None:
            # key expires should be a timedelta, so if it's a datetime, turn it into a timedelta
            if isinstance(key_expires, datetime):
                key_expires = key_expires - self.created

            sig._signature.subpackets.addnew('KeyExpirationTime',
                                             hashed=True,
                                             expires=key_expires)

        if cipher_prefs is not None:
            sig._signature.subpackets.addnew('PreferredSymmetricAlgorithms',
                                             hashed=True,
                                             flags=cipher_prefs)

        if hash_prefs:
            sig._signature.subpackets.addnew('PreferredHashAlgorithms',
                                             hashed=True,
                                             flags=hash_prefs)
            if sig.hash_algorithm is None:
                sig._signature.halg = hash_prefs[0]
        if sig.hash_algorithm is None:
            sig._signature.halg = HashAlgorithm.SHA256

        if compression_prefs is not None:
            sig._signature.subpackets.addnew('PreferredCompressionAlgorithms',
                                             hashed=True,
                                             flags=compression_prefs)

        if keyserver_flags is not None:
            sig._signature.subpackets.addnew('KeyServerPreferences',
                                             hashed=True,
                                             flags=keyserver_flags)

        if keyserver is not None:
            sig._signature.subpackets.addnew('PreferredKeyServer',
                                             hashed=True,
                                             uri=keyserver)

        if primary_uid is not None:
            sig._signature.subpackets.addnew('PrimaryUserID',
                                             hashed=True,
                                             primary=primary_uid)

        # Features is always set on self-signatures
        sig._signature.subpackets.addnew('Features',
                                         hashed=True,
                                         flags=Features.pgpy_features)

    else:
        # signature options that only make sense in non-self-certifications
        trust = prefs.pop('trust', None)
        regex = prefs.pop('regex', None)

        if trust is not None:
            sig._signature.subpackets.addnew('TrustSignature',
                                             hashed=True,
                                             level=trust[0],
                                             amount=trust[1])

            if regex is not None:
                sig._signature.subpackets.addnew('RegularExpression',
                                                 hashed=True,
                                                 regex=regex)

    return self._sign(subject, sig, **prefs)
def patched_pgpy_sign(key: PGPKey, subject, **prefs):
    # pylint: disable=protected-access
    sig = PGPSignature.new(SignatureType.BinaryDocument, key.key_algorithm,
                           None, key.fingerprint.keyid)
    # noinspection PyProtectedMember
    return key._sign(subject, sig, **prefs)
Esempio n. 19
0
 def test_parse_wrong_contents(self):
     notsigtext = _read('tests/testdata/blocks/message.compressed.asc').replace('MESSAGE', 'SIGNATURE')
     sig = PGPSignature()
     with pytest.raises(ValueError):
         sig.parse(notsigtext)
Esempio n. 20
0
def verify_by_ca(data, raw_sign):
    ca_pub_key = current_app.config['CA_PUB_KEY']
    sign = PGPSignature.from_blob(raw_sign)
    return ca_pub_key.verify(data, sign)