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)
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_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)
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
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
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")
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)
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)
def test_or_typeerror(self): with pytest.raises(TypeError): PGPSignature() | 12
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)
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
def test_or_typeerror(self): sig = PGPSignature() with pytest.raises(TypeError): sig |= None
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)
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)
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)
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)