def generate_keys(gpg: gnupg.GPG, company_name: str, targer_folder: str): company_path, public_file_name, secret_file_name = __get_absolut_filepath( company_name=company_name) configuration_kwargs = utils.get_configuratation( path=os.path.join(targer_folder, 'configuration')) os.makedirs(company_path, exist_ok=True) gpg_keys = gpg.gen_key_input(**configuration_kwargs.get('array')) key = gpg.gen_key(gpg_keys) ascii_armored_public_keys = gpg.export_keys(key.fingerprint) ascii_armored_private_keys = gpg.export_keys( key.fingerprint, secret=True, passphrase=configuration_kwargs.get('array')['passphrase'], ) with open(public_file_name, 'w') as file: file.write(ascii_armored_public_keys) logger.info(f'Generate file to export to customer done') with open(secret_file_name, 'w') as file: file.write(ascii_armored_public_keys) file.write(ascii_armored_private_keys) logger.info(f'Generate file to use done') _clean_directory(path=settings.PROJECT_NAME)
def test_check_git_commits_ok(): with TemporaryDirectory() as tmp_git_repo: gpg_tmp_home = os.path.join(tmp_git_repo, 'gpg_tmp_home') # Included in the repository to avoid problems with low entropy in CI # environments. # input_data = gpg.gen_key_input( # key_type='RSA', # subkey_type='RSA', # key_length=1024, # subkey_length=1024, # name_comment='This is only a test key who’s private key is publicly know. Don’t use this key for anything!1!', # name_email='*****@*****.**', # # Has already expired at the time of creation to ensure no one will ever use the key. # expire_date='2012-12-24', # Needs to be set to the 24 for the key to expire on 23. # # Hm, Ok, gpg does not do that by default. `--faked-system-time` # # could be used to force it but that would require cmd access. # # https://www.gnupg.org/documentation/manuals/gnupg/Unattended-GPG-key-generation.html # # "gpg: Invalid option "--faked-system-time"" :( # # Only: gpg2 --batch --gen-key --debug=0 --faked-system-time '2342-05-23' # # has been confirmed to work from current Debian Stretch. # # Faking it manually anyway … # ) # print(input_data) # print(gpg.gen_key(input_data)) shutil.copytree(debops_keyring_fake_gnupg_home, gpg_tmp_home) gpg = GPG(gnupghome=gpg_tmp_home) os.chmod(gpg_tmp_home, 0o700) for r, d, f in os.walk(gpg_tmp_home): os.chmod(r, 0o700) gpg_key_fingerprint = gpg.list_keys()[0]['fingerprint'] gpg_edit_key_cmd = subprocess.Popen( ['gpg', '--homedir', gpg_tmp_home, '--command-fd', '0', '--batch', '--edit-key', gpg_key_fingerprint], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) (gpg_edit_key_cmd_stdout, gpg_edit_key_cmd_stderr) = gpg_edit_key_cmd.communicate( input='expire\n0\nsave\n'.encode(), timeout=5, ) # print(gpg_edit_key_cmd_stderr.decode()) # print(subprocess.check_output(['gpg', '--homedir', gpg_tmp_home, '--list-public-keys']).decode()) if 'expires: never' not in str(gpg_edit_key_cmd_stderr): raise Exception("Could not change expiration date.") tmp_keyring_dir = os.path.join(tmp_git_repo, 'tmp-keyring-gpg') tmp_pubkey_file = os.path.join( tmp_keyring_dir, '0x' + gpg_key_fingerprint[-16:].upper() ) os.mkdir(tmp_keyring_dir) with open(tmp_pubkey_file, 'w') as tmp_pubkey_fh: tmp_pubkey_fh.write(gpg.export_keys(gpg_key_fingerprint)) git_cmd = git.Git(tmp_git_repo) git_cmd.update_environment( GNUPGHOME=debops_keyring_fake_gnupg_home, ) git_cmd.init() git_cmd.config(['user.signingkey', gpg_key_fingerprint]) git_cmd.config(['user.email', '*****@*****.**']) git_cmd.config(['user.name', 'debops-keyring-test']) git_cmd.update_environment( GNUPGHOME=os.path.join(tmp_git_repo, 'gpg_tmp_home'), ) tmp_git_file = os.path.join(tmp_git_repo, 'new-file') with open(tmp_git_file, 'w') as tmp_git_fh: tmp_git_fh.write(str(time.time())) git_cmd.add([tmp_git_file]) git_cmd.commit(['--gpg-sign', '--message', 'Signed commit']) debops_keyring = Keyring( keyring_name=tmp_keyring_dir, ) debops_keyring.check_git_commits(tmp_git_repo) # Now make an unsigned commit to ensure that this raises an exception. with open(tmp_git_file, 'w') as tmp_git_fh: tmp_git_fh.write(str(time.time())) git_cmd.add([tmp_git_file]) git_cmd.commit(['--no-gpg-sign', '--message', 'Unsigned commit']) try: debops_keyring.check_git_commits(tmp_git_repo) assert False except Exception as e: if 'OpenPGP signature of commit could not be verified' in str(e) and 'Unsigned commit' in str(e): assert True else: assert False
class Test(unittest.TestCase): '''Unit tests for validating signed envelopes from the Learning Registry''' def __init__(self, methodName="runTest"): self.sampleJSON = ''' { "_id":"00e3f67232e743b6bc2a079bd98ff55a", "_rev":"1-8163d32f6cc9996f2b7228d8b5db7962", "doc_type":"resource_data", "update_timestamp":"2011-03-14 13:36:04.617999", "resource_data":"<oai_dc:dc xmlns:oai_dc=\\"http://www.openarchives.org/OAI/2.0/oai_dc/\\" xmlns:dc=\\"http://purl.org/dc/elements/1.1/\\" xmlns:xsi=\\"http://www.w3.org/2001/XMLSchema-instance\\" xmlns=\\"http://www.openarchives.org/OAI/2.0/\\" xsi:schemaLocation=\\"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd\\">\\n<dc:title>A chat about America. October and November, 1884.</dc:title>\\n<dc:creator>J. P.</dc:creator>\\n<dc:subject>United States--Description and travel.</dc:subject>\\n<dc:description>\\"Printed for private circulation only.\\"</dc:description>\\n<dc:description>Electronic reproduction. Washington, D.C. : Library of Congress, [2002-2003]</dc:description>\\n<dc:publisher>Manchester, Palmer & Howe</dc:publisher>\\n<dc:date>1885</dc:date>\\n<dc:type>text</dc:type>\\n<dc:identifier>http://hdl.loc.gov/loc.gdc/lhbtn.12281</dc:identifier>\\n<dc:language>eng</dc:language>\\n<dc:coverage>United States</dc:coverage>\\n</oai_dc:dc>\\n ", "keys":["United States--Description and travel.","eng"], "submitter_type":"agent", "resource_data_type":"metadata", "payload_schema_locator":"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd", "payload_placement":"inline", "submitter":"NSDL 2 LR Data Pump", "payload_schema":["oai_dc"], "node_timestamp":"2011-03-14 13:36:04.617999", "doc_version":"0.10.0", "create_timestamp":"2011-03-14 13:36:04.617999", "active":true, "publishing_node":"string", "resource_locator":"http://hdl.loc.gov/loc.gdc/lhbtn.12281", "doc_ID":"00e3f67232e743b6bc2a079bd98ff55a", "TOS": { "submission_TOS": "http://example.com/tos/unknown", "submission_attribution": "unidentified" } } ''' self.sampleKeyLocations = [ "http://example.com/mykey", "http://example2.com/mykey" ] self.gpgbin = "gpg" self.gnupgHome = os.path.expanduser( os.path.abspath(os.path.join("..", "gnupg_home"))) self.gpg = None self.testDataDir = None self.testDataUnicode = None configFile = os.path.join("config.cfg") if os.path.exists(configFile): config = json.load(file(configFile)) if "global" in config: if "testdata" in config["global"] and os.path.exists( config["global"]["testdata"]): self.testDataDir = config["global"]["testdata"] if "testdata_unicode" in config["global"] and os.path.exists( config["global"]["testdata_unicode"]): self.testDataUnicode = config["global"]["testdata_unicode"] unittest.TestCase.__init__(self, methodName) def setUp(self): now = time.localtime() now = calendar.timegm(now) try: for root, dirs, files in os.walk(self.gnupgHome): for filename in files: try: os.unlink(os.path.join(root, filename)) except: pass os.removedirs(root) except: pass os.makedirs(self.gnupgHome) self.gpg = GPG(gpgbinary=self.gpgbin, gnupghome=self.gnupgHome) self.privateEmail = "privateTest-{0}@learningregistry.org".format(now) self.privateEmail2 = "privateTest2-{0}@learningregistry.org".format( now) self.genericPassphrase = "supersecret" input = self.gpg.gen_key_input(name_email=self.privateEmail, passphrase=self.genericPassphrase) self.privateKey = self.gpg.gen_key(input) input = self.gpg.gen_key_input(name_email=self.privateEmail2, passphrase=self.genericPassphrase) self.privateKey2 = self.gpg.gen_key(input) self.privExport = self.gpg.export_keys( [self.privateKey.fingerprint, self.privateKey2.fingerprint], secret=True) self.pubExport = self.gpg.export_keys( [self.privateKey.fingerprint, self.privateKey2.fingerprint], secret=False) pass def tearDown(self): self.gpg.delete_keys( [self.privateKey.fingerprint, self.privateKey2.fingerprint], secret=True) self.gpg.delete_keys( [self.privateKey.fingerprint, self.privateKey2.fingerprint], secret=False) pass def testGetSignatureBlock(self): '''Check that signature block validation correctly returns a structurally valid response''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "envelope did not sign correctly" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) sigInfo = verifytool._getSignatureInfo(signed) assert sigInfo != None, "signature extraction from envelope failed" assert "signing_method" in sigInfo and sigInfo[ "signing_method"] == verifytool.signatureMethod, "signing_method is missing from signature block" assert "signature" in sigInfo and sigInfo["signature"] != None and len( sigInfo["signature"] ) > 0, "signature field is missing, null or is empty" assert "key_location" in sigInfo and sigInfo[ "key_location"] == self.sampleKeyLocations, "key_location field is not correct" assert "key_owner" in sigInfo and sigInfo[ "key_owner"] == signtool._get_privatekey_owner( ), "key_owner field does not match signing key" def testBadSignatureBlockMissingLocation(self): '''Check that signature block validation correctly checks for missing key_location field''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=None) signed = signtool.sign(unsigned) assert signed != None, "Envelope not signed correctly" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) with self.assertRaises(errors.BadSignatureFormat, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.message == errors.MISSING_KEY_LOCATION, "Exception not formatted with correct message" def testBadSignatureBlockMissingSignatureMethod(self): '''Check signature block for missing signature_method detection''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "Envelope not signed correctly." del signed["digital_signature"]["signing_method"] verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) with self.assertRaises(errors.UnsupportedSignatureAlgorithm, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.alg == None, "Raised exception not formatted correctly" def testBadSignatureBlockBadSignatureMethod(self): '''Check signature block for detecting unsupported algorithm use''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None signed["digital_signature"][ "signing_method"] = signtool.signatureMethod + "+BAD_SIGNATURE_METHOD" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) with self.assertRaises(errors.UnsupportedSignatureAlgorithm, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.alg == signed["digital_signature"][ "signing_method"], "Exception not raised correctly." def testBadSignatureBlockBadKeyOwner(self): '''Check signature block for a bad key_owner field''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "Envelope not signed correctly" signed["digital_signature"]["key_owner"] = [ "John Q. Public <*****@*****.**>" ] verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) with self.assertRaises(errors.BadSignatureFormat, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.message == errors.BAD_KEY_OWNER, "Wrong exception" def testBadSignatureBlockMissingNullEmptySignature(self): '''Check signature block validation with missing/null or empty signature''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "Envelope signing did not succeed correctly." verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) signed["digital_signature"]["signature"] = "" with self.assertRaises(errors.BadSignatureFormat, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.message == errors.MISSING_SIGNATURE, "Wrong exception raised" signed["digital_signature"]["signature"] = None with self.assertRaises(errors.BadSignatureFormat, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.message == errors.MISSING_SIGNATURE, "Wrong exception raised" del signed["digital_signature"]["signature"] with self.assertRaises(errors.BadSignatureFormat, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.message == errors.MISSING_SIGNATURE, "Wrong exception raised" def testValidSignature(self): '''Check for valid signature''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "Envelope did not sign correctly" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) verified = verifytool.verify(signed) assert verified == True, "Envelope signature verification did not succeed, even though it should" def testMissingPublicKey(self): '''Check for appropriate response when public key for signature is missing''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "Envelope did not sign correctly" self.gpg.delete_keys([self.privateKey.fingerprint], secret=True) self.gpg.delete_keys([self.privateKey.fingerprint], secret=False) verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) with self.assertRaises(errors.MissingPublicKey, msg="Expected exception not raised.") as caught: verified = verifytool.verify(signed) assert verified == False, "Envelope verified, despite missing public key." def testCorruptEnvelope(self): '''Modify a signed envelope and check for validity''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "envelope did not get signed correctly" signed["X_corrupted"] = "Corrupted Envelope" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) verified = verifytool.verify(signed) assert verified == False, "corrupted envelope verified as good" def testWrongSignature(self): '''Test using a mis-matched signature, using a signature from a different valid envelope''' unsigned = json.loads(self.sampleJSON) altered = copy.deepcopy(unsigned) altered["X_corrupted"] = "Altered Envelope" signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signtool2 = Sign_0_21(privateKeyID=self.privateKey2.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) alt_signed = signtool2.sign(altered) assert signed != None, "original did not get signed" assert alt_signed != None, "modified copy did not get signed" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) verified = verifytool.verify(signed) assert verified == True, "signature did not verify, even though it should." verified = verifytool.verify(alt_signed) assert verified == True, "signature did not verify, even though it should." signed["digital_signature"] = alt_signed["digital_signature"] verified = verifytool.verify(signed) assert verified == False, "swapped signature block validated envelope as good." def testCorruptSignature(self): '''Test using a corrupted signature, replace the hash within a signature with a hash from a different envelope''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "baseline signing failed" # validate original with good signature verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) verified = verifytool.verify(signed) assert verified == True, "baseline validation failed" # manipulate the hash portion of a signature block altered = copy.deepcopy(unsigned) altered["X_corrupted"] = "Altered Envelope" altered_hash = signtool.get_message(altered) validHash = verifytool._extractHashFromSignature( signed["digital_signature"]["signature"]) alt_signed = copy.deepcopy(signed) alt_signed["digital_signature"]["signature"] = signed[ "digital_signature"]["signature"].replace(validHash, altered_hash) assert alt_signed["digital_signature"]["signature"] != signed[ "digital_signature"][ "signature"], "envelopes should not be equal after deliberate modificaton" verified = verifytool.verify(alt_signed) assert verified == False, "verification failed, corrupted signature block verified as good" def testSignLRTestData(self): '''Test using LR Test Data, if available''' if self.testDataDir == None: log.info("Skipping test, test data directory not set.") return import codecs signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) allfiles = os.listdir(self.testDataDir) for root, dirs, files in os.walk(self.testDataDir): for fileName in files: log.info("Trying to sign %s" % (fileName, )) unsigned = json.load( codecs.open(os.path.join(root, fileName), "r", "utf-8-sig")) signed = signtool.sign(unsigned) assert "digital_signature" in signed, "missing digital_signature" verified = verifytool.verify(signed) assert verified == True, "baseline validation failed"
def import_from_dump(file): """Import from an SKS dump.""" # First, load a new GPG instance. gpg = GPG(gnupghome="/tmp/skier-import") # Read data in dumpf = open(file, 'rb') data = dumpf.read() dump = pgpdump.BinaryData(data) dumpf.close() # Import the keydump into gpg try: gpg.import_keys(data) except: # Yeah, whatever. pass """ # Read in packets packets_flat = [] try: for packet in dump.packets(): packets_flat.append(packet) except Exception as e: # Some SKS data is malformed. print("SKS data in {} is malformed - truncating at packet {}".format(file, len(packets_flat)+1)) # Unflatten list into sublists, starting at each new Publickey packet. packets = [] tmpl = [] for packet in packets_flat: if isinstance(packet, pgpdump.packet.PublicKeyPacket) and not isinstance(packet, pgpdump.packet.PublicSubkeyPacket) and tmpl: tmpl.insert(0, packet) gpg_output = gpg.export_keys(keyids=[packet.fingerprint.decode()]) if gpg_output: tmpl.append(gpg_output) packets.append(tmpl) tmpl = [] continue else: tmpl.append(packet) packets.append(tmpl) """ armored = [] for key in gpg.list_keys(): tmpkey = gpg.export_keys(keyids=key['fingerprint']) if not tmpkey: print("{} is malformed - not importing".format(key['fingerprint'])) armored.append(tmpkey) print("Importing {} keys".format(len(armored))) """ for gpack in packets: keyinfo = KeyInfo.pgp_dump(None, packets=gpack) dbob = db.Key.from_keyinfo(keyinfo) db.db.session.add(dbob) db.db.session.commit() """ for key in armored: kyinfo = KeyInfo.pgp_dump(key) if not kyinfo.fingerprint: print("Key {} is malformed - cannot be imported".format(kyinfo)) else: dbob = db.Key.from_keyinfo(kyinfo) db.db.session.add(dbob) db.db.session.commit() shutil.rmtree("/tmp/skier-import")
def finish_login(message, bot, settings): user_root_folder = '/Seppass/Users_folder/user_' + str(message.chat.id) try: if not path.isdir(user_root_folder+'/main'): makedirs(user_root_folder+'/main') if not path.isdir(user_root_folder+'/user_data'): makedirs(user_root_folder+'/user_data') except: msg = bot.send_message(message.chat.id, 'Произошла ошибка.') del_mess(msg, bot, 4) return try: gpg = GPG() input_data = gpg.gen_key_input( passphrase=message.text, name_real='user_'+str(message.chat.id) ) key = gpg.gen_key(input_data) key = key.fingerprint ascii_armored_private_keys = gpg.export_keys(key, True, passphrase=message.text) system('echo RELOADAGENT | gpg-connect-agent') with open(user_root_folder+'/user_data/gpg_private_key.asc', 'w') as f: f.write(ascii_armored_private_keys) with open(user_root_folder+'/main/gpg_private_key.asc', 'w') as f: f.write(ascii_armored_private_keys) except: msg = bot.send_message(message.chat.id, 'Произошла ошибка.') del_mess(msg, bot, 4) return try: data = (('user_'+str(message.chat.id), key, str(settings))) conn = connect('DataBase.db', check_same_thread=False) c = conn.cursor() query = "INSERT INTO Users VALUES (?, ?, ?)" c.execute(query, data) conn.commit() conn.close() except: msg = bot.send_message(message.chat.id, 'Произошла ошибка.') del_mess(msg, bot, 4) return markup = types.ReplyKeyboardMarkup(one_time_keyboard=True) markup.add('Да') if settings["store_pass"] == "pass_server": try: with open(user_root_folder+'/user_data/Nothing.txt', 'w') as f: f.write(message.text) except: msg = bot.send_message(message.chat.id, 'Произошла ошибка.') del_mess(msg, bot, 4) return msg_handler = bot.send_message(message.chat.id, 'Регистрация прошла успешно. Пароль храниться на сервере.\n\nВаш user id:\n'+str(message.chat.id)+'\n\nПароль:\n'+ message.text +'\n\nЭто ваш отпечаток ключа:\n'+ str(key)+'\n\nЗапомнили? Я сейчас это сообщение удалю, в целях сохранности ваших данных.', reply_markup = markup) bot.register_next_step_handler(msg_handler, lambda msg: complete_finish_login(msg, bot)) else: msg_handler = bot.send_message(message.chat.id, 'Регистрация прошла успешно. Запомните пароль, в случае его утери ваш акк не восстановить (пока).\n\nВаш user id:\n'+str(message.chat.id)+'\n\nПароль:\n'+ message.text +'\n\nЭто ваш отпечаток ключа:\n'+ str(key)+'\n\nЗапомнили? Я сейчас это сообщение удалю, в целях сохранности ваших данных.', reply_markup = markup) bot.register_next_step_handler(msg_handler, lambda msg: complete_finish_login(msg, bot))
class Test(unittest.TestCase): '''Unit tests for validating signed envelopes from the Learning Registry''' def __init__(self, methodName="runTest"): self.sampleJSON = ''' { "_id":"00e3f67232e743b6bc2a079bd98ff55a", "_rev":"1-8163d32f6cc9996f2b7228d8b5db7962", "doc_type":"resource_data", "update_timestamp":"2011-03-14 13:36:04.617999", "resource_data":"<oai_dc:dc xmlns:oai_dc=\\"http://www.openarchives.org/OAI/2.0/oai_dc/\\" xmlns:dc=\\"http://purl.org/dc/elements/1.1/\\" xmlns:xsi=\\"http://www.w3.org/2001/XMLSchema-instance\\" xmlns=\\"http://www.openarchives.org/OAI/2.0/\\" xsi:schemaLocation=\\"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd\\">\\n<dc:title>A chat about America. October and November, 1884.</dc:title>\\n<dc:creator>J. P.</dc:creator>\\n<dc:subject>United States--Description and travel.</dc:subject>\\n<dc:description>\\"Printed for private circulation only.\\"</dc:description>\\n<dc:description>Electronic reproduction. Washington, D.C. : Library of Congress, [2002-2003]</dc:description>\\n<dc:publisher>Manchester, Palmer & Howe</dc:publisher>\\n<dc:date>1885</dc:date>\\n<dc:type>text</dc:type>\\n<dc:identifier>http://hdl.loc.gov/loc.gdc/lhbtn.12281</dc:identifier>\\n<dc:language>eng</dc:language>\\n<dc:coverage>United States</dc:coverage>\\n</oai_dc:dc>\\n ", "keys":["United States--Description and travel.","eng"], "submitter_type":"agent", "resource_data_type":"metadata", "payload_schema_locator":"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd", "payload_placement":"inline", "submitter":"NSDL 2 LR Data Pump", "payload_schema":["oai_dc"], "node_timestamp":"2011-03-14 13:36:04.617999", "doc_version":"0.10.0", "create_timestamp":"2011-03-14 13:36:04.617999", "active":true, "publishing_node":"string", "resource_locator":"http://hdl.loc.gov/loc.gdc/lhbtn.12281", "doc_ID":"00e3f67232e743b6bc2a079bd98ff55a", "TOS": { "submission_TOS": "http://example.com/tos/unknown", "submission_attribution": "unidentified" } } ''' self.sampleKeyLocations = [ "http://example.com/mykey", "http://example2.com/mykey" ] self.gpgbin="/usr/local/bin/gpg" self.gnupgHome = os.path.expanduser(os.path.join("~", ".gnupg")) self.gpg = GPG(gpgbinary=self.gpgbin, gnupghome=self.gnupgHome) self.testDataDir = None configFile = os.path.join("config.cfg") if os.path.exists(configFile): config = json.load(file(configFile)) if config.has_key("global"): if config["global"].has_key("testdata") and os.path.exists(config["global"]["testdata"]): self.testDataDir = config["global"]["testdata"] unittest.TestCase.__init__(self, methodName) def setUp(self): now = time.localtime() now = calendar.timegm(now) self.privateEmail = "privateTest-{0}@learningregistry.org".format(now) self.privateEmail2 = "privateTest2-{0}@learningregistry.org".format(now) self.genericPassphrase = "supersecret" input = self.gpg.gen_key_input(name_email=self.privateEmail, passphrase=self.genericPassphrase) self.privateKey = self.gpg.gen_key(input) input = self.gpg.gen_key_input(name_email=self.privateEmail2, passphrase=self.genericPassphrase) self.privateKey2 = self.gpg.gen_key(input) self.privExport = self.gpg.export_keys([self.privateKey.fingerprint, self.privateKey2.fingerprint], secret=True) self.pubExport = self.gpg.export_keys([self.privateKey.fingerprint, self.privateKey2.fingerprint], secret=False) pass def tearDown(self): self.gpg.delete_keys([self.privateKey.fingerprint, self.privateKey2.fingerprint], secret=True) self.gpg.delete_keys([self.privateKey.fingerprint, self.privateKey2.fingerprint], secret=False) pass def testGetSignatureBlock(self): '''Check that signature block validation correctly returns a structurally valid response''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "envelope did not sign correctly" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) sigInfo = verifytool._getSignatureInfo(signed) assert sigInfo != None, "signature extraction from envelope failed" assert sigInfo.has_key("signing_method") and sigInfo["signing_method"] == verifytool.signatureMethod, "signing_method is missing from signature block" assert sigInfo.has_key("signature") and sigInfo["signature"] != None and len(sigInfo["signature"]) > 0, "signature field is missing, null or is empty" assert sigInfo.has_key("key_location") and sigInfo["key_location"] == self.sampleKeyLocations, "key_location field is not correct" assert sigInfo.has_key("key_owner") and sigInfo["key_owner"] == signtool._get_privatekey_owner(), "key_owner field does not match signing key" def testBadSignatureBlockMissingLocation(self): '''Check that signature block validation correctly checks for missing key_location field''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=None) signed = signtool.sign(unsigned) assert signed != None, "Envelope not signed correctly" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) with self.assertRaises(errors.BadSignatureFormat, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.message == errors.MISSING_KEY_LOCATION, "Exception not formatted with correct message" def testBadSignatureBlockMissingSignatureMethod(self): '''Check signature block for missing signature_method detection''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "Envelope not signed correctly." del signed["digital_signature"]["signing_method"] verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) with self.assertRaises(errors.UnsupportedSignatureAlgorithm, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.alg == None, "Raised exception not formatted correctly" def testBadSignatureBlockBadSignatureMethod(self): '''Check signature block for detecting unsupported algorithm use''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None signed["digital_signature"]["signing_method"] = signtool.signatureMethod+"+BAD_SIGNATURE_METHOD" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) with self.assertRaises(errors.UnsupportedSignatureAlgorithm, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.alg == signed["digital_signature"]["signing_method"], "Exception not raised correctly." def testBadSignatureBlockBadKeyOwner(self): '''Check signature block for a bad key_owner field''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "Envelope not signed correctly" signed["digital_signature"]["key_owner"] = ["John Q. Public <*****@*****.**>"] verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) with self.assertRaises(errors.BadSignatureFormat, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.message == errors.BAD_KEY_OWNER, "Wrong exception" def testBadSignatureBlockMissingNullEmptySignature(self): '''Check signature block validation with missing/null or empty signature''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "Envelope signing did not succeed correctly." verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) signed["digital_signature"]["signature"] = "" with self.assertRaises(errors.BadSignatureFormat, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.message == errors.MISSING_SIGNATURE, "Wrong exception raised" signed["digital_signature"]["signature"] = None with self.assertRaises(errors.BadSignatureFormat, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.message == errors.MISSING_SIGNATURE, "Wrong exception raised" del signed["digital_signature"]["signature"] with self.assertRaises(errors.BadSignatureFormat, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.message == errors.MISSING_SIGNATURE, "Wrong exception raised" def testValidSignature(self): '''Check for valid signature''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "Envelope did not sign correctly" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) verified = verifytool.verify(signed) assert verified == True, "Envelope signature verification did not succeed, even though it should" def testMissingPublicKey(self): '''Check for appropriate response when public key for signature is missing''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "Envelope did not sign correctly" self.gpg.delete_keys([self.privateKey.fingerprint], secret=True) self.gpg.delete_keys([self.privateKey.fingerprint], secret=False) verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) with self.assertRaises(errors.MissingPublicKey, msg="Expected exception not raised.") as caught: verified = verifytool.verify(signed) assert verified == False, "Envelope verified, despite missing public key." def testCorruptEnvelope(self): '''Modify a signed envelope and check for validity''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "envelope did not get signed correctly" signed["X_corrupted"] = "Corrupted Envelope" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) verified = verifytool.verify(signed) assert verified == False, "corrupted envelope verified as good" def testWrongSignature(self): '''Test using a mis-matched signature, using a signature from a different valid envelope''' unsigned = json.loads(self.sampleJSON) altered = copy.copy(unsigned) altered["X_corrupted"] = "Altered Envelope" signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signtool2 = Sign_0_21(privateKeyID=self.privateKey2.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) alt_signed = signtool2.sign(altered) assert signed != None, "original did not get signed" assert alt_signed != None, "modified copy did not get signed" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) verified = verifytool.verify(signed) assert verified == True, "signature did not verify, even though it should." verified = verifytool.verify(alt_signed) assert verified == True, "signature did not verify, even though it should." signed["digital_signature"] = alt_signed["digital_signature"] verified = verifytool.verify(signed) assert verified == False, "swapped signature block validated envelope as good." def testCorruptSignature(self): '''Test using a corrupted signature, replace the hash within a signature with a hash from a different envelope''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "baseline signing failed" # validate original with good signature verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) verified = verifytool.verify(signed) assert verified == True, "baseline validation failed" # manipulate the hash portion of a signature block altered = copy.copy(unsigned) altered["X_corrupted"] = "Altered Envelope" altered_hash = signtool.get_message(altered) validHash = verifytool._extractHashFromSignature(signed["digital_signature"]["signature"]) alt_signed = copy.deepcopy(signed) alt_signed["digital_signature"]["signature"] = signed["digital_signature"]["signature"].replace(validHash, altered_hash) assert alt_signed["digital_signature"]["signature"] != signed["digital_signature"]["signature"], "envelopes should not be equal after deliberate modificaton" verified = verifytool.verify(alt_signed) assert verified == False, "verification failed, corrupted signature block verified as good" def testSignLRTestData(self): '''Test using LR Test Data, if available''' if self.testDataDir == None: log.info("Skipping test, test data directory not set.") return import codecs signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) allfiles = os.listdir(self.testDataDir) for fileName in allfiles: log.info("Trying to sign %s" % (fileName, )) unsigned = json.load(codecs.open(os.path.join(self.testDataDir, fileName), "r", "utf-8-sig")) signed = signtool.sign(unsigned) assert signed.has_key("digital_signature"), "missing digital_signature" verified = verifytool.verify(signed) assert verified == True, "baseline validation failed"
def setUp(self): """ Construct environment. Here, we adopt the configuration used by the production or development installation and make the necessary changes before writing it to a new file in the etc directory. When we're finished, we'll remove it in the tearDown() function. """ if not os.path.exists(self.client_env['CONFDIR']): # Don't waste time and entropy on keys if we can't write configuration # files -- that's a very distressing experience. assert len(sys.argv) == 2 # Prepare two GPG keypairs; one for the agent, one for the client agent_gpg_dir = os.path.join(self.client_env['CONFDIR'], 'agent_gpg') agent_gpg = GPG(gnupghome=agent_gpg_dir) agent_key = agent_gpg.gen_key(agent_gpg.gen_key_input(**self.gpg_params)) client_gpg_dir = os.path.join(self.client_env['CONFDIR'], 'client_gpg') client_gpg = GPG(gnupghome=client_gpg_dir) client_key = client_gpg.gen_key(client_gpg.gen_key_input(**self.gpg_params)) # Export both public keys; import them into the opposing side agent_key_blob = agent_gpg.export_keys(agent_key.fingerprint) client_gpg.import_keys(agent_key_blob) client_gpg.sign_key(agent_key.fingerprint) client_key_blob = client_gpg.export_keys(client_key.fingerprint) agent_gpg.import_keys(client_key_blob) agent_gpg.sign_key(client_key.fingerprint) # Configure the agent to run in a development-safe configuration. # # Here, we load the base configuration we ship with the application # as the default. All other configuration will be ignored for the # purposes of the test run, since this is outside of our scope. with open(self.agent_env['CONFDIR'], 'w') as f: l = os.path.join(self.client_env['CONFDIR'], 'agent_%s.log') agent_cfg = ConfigurationFactory.get('hypernova.agent', root_dir=sys.argv[1]) agent_cfg.set('server', 'address', self.agent_addr[0]) agent_cfg.set('server', 'port', self.agent_addr[1]) agent_cfg.set('server', 'daemon', 'false') agent_cfg.set('gpg', 'key_store', agent_gpg_dir) agent_cfg.set('gpg', 'fingerprint', agent_key.fingerprint) agent_cfg.set('logging', 'main_log', l %('main')) agent_cfg.set('logging', 'request_log', l %('request')) agent_cfg.set('logging', 'error_log', l %('error')) agent_cfg.write(f) # The client has to use two different configuration files, both in # the same directory. client_cfg_dir = self.client_env['CONFDIR'] # Configure the client to use its temporary key. # # To communicate with the agent (which will be running in a limited # testing mode), we'll need to reconfigure the client with a keypair # we've imported into the agent. This keystore manipulation has # already taken place, so we know the fingerprint of our new private # key. client_cfg_file = os.path.join(client_cfg_dir, 'client.ini') with open(client_cfg_file, 'w') as f: client_cfg = configparser.SafeConfigParser() client_cfg.add_section('client') client_cfg.set('client', 'privkey', client_key.fingerprint) client_cfg.write(f) # Pair the client to the agent. # # We do this manually, since the importer requires that we write the # public key to a file before we import it. This would be a # pointless exercise and an unnecessary complication. client_srv_file = os.path.join(client_cfg_dir, 'servers.ini') with open(client_srv_file, 'w') as f: client_srv_cfg = configparser.SafeConfigParser() client_srv_cfg.add_section('local') client_srv_cfg.set('local', 'addr', ':'.join(self.agent_addr)) client_srv_cfg.set('local', 'pubkey', agent_key.fingerprint) client_srv_cfg.write(f) # TODO: instead of lazily and unreliably falling asleep on the job, # we should probably use a regular expression to check the output. # Time is of the essence, though! # No, we'll use pexpect instead, since it's now shipped as a py3k # dependency. agent_cmd = [ 'hn-agent', self.agent_env['CONFDIR'] ] self.agent_proc = subprocess.Popen(agent_cmd, env=self.agent_env, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) time.sleep(self.agent_init_time)
def test_check_git_commits_ok(): with TemporaryDirectory() as tmp_git_repo: gpg_tmp_home = os.path.join(tmp_git_repo, 'gpg_tmp_home') # Included in the repository to avoid problems with low entropy in CI # environments. # input_data = gpg.gen_key_input( # key_type='RSA', # subkey_type='RSA', # key_length=1024, # subkey_length=1024, # name_comment='This is only a test key who’s private key is publicly know. Don’t use this key for anything!1!', # name_email='*****@*****.**', # # Has already expired at the time of creation to ensure no one will ever use the key. # expire_date='2012-12-24', # Needs to be set to the 24 for the key to expire on 23. # # Hm, Ok, gpg does not do that by default. `--faked-system-time` # # could be used to force it but that would require cmd access. # # https://www.gnupg.org/documentation/manuals/gnupg/Unattended-GPG-key-generation.html # # "gpg: Invalid option "--faked-system-time"" :( # # Only: gpg2 --batch --gen-key --debug=0 --faked-system-time '2342-05-23' # # has been confirmed to work from current Debian Stretch. # # Faking it manually anyway … # ) # print(input_data) # print(gpg.gen_key(input_data)) shutil.copytree(debops_keyring_fake_gnupg_home, gpg_tmp_home) gpg = GPG(gnupghome=gpg_tmp_home) os.chmod(gpg_tmp_home, 0o700) for r, d, f in os.walk(gpg_tmp_home): os.chmod(r, 0o700) gpg_key_fingerprint = gpg.list_keys()[0]['fingerprint'] gpg_edit_key_cmd = subprocess.Popen( [ 'gpg', '--homedir', gpg_tmp_home, '--command-fd', '0', '--batch', '--edit-key', gpg_key_fingerprint ], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) (gpg_edit_key_cmd_stdout, gpg_edit_key_cmd_stderr) = gpg_edit_key_cmd.communicate( input='expire\n0\nsave\n'.encode(), timeout=5, ) # print(gpg_edit_key_cmd_stderr.decode()) # print(subprocess.check_output(['gpg', '--homedir', gpg_tmp_home, '--list-public-keys']).decode()) if 'expires: never' not in str(gpg_edit_key_cmd_stderr): raise Exception("Could not change expiration date.") tmp_keyring_dir = os.path.join(tmp_git_repo, 'tmp-keyring-gpg') tmp_pubkey_file = os.path.join( tmp_keyring_dir, '0x' + gpg_key_fingerprint[-16:].upper()) os.mkdir(tmp_keyring_dir) with open(tmp_pubkey_file, 'w') as tmp_pubkey_fh: tmp_pubkey_fh.write(gpg.export_keys(gpg_key_fingerprint)) git_cmd = git.Git(tmp_git_repo) git_cmd.update_environment(GNUPGHOME=debops_keyring_fake_gnupg_home, ) git_cmd.init() git_cmd.config(['user.signingkey', gpg_key_fingerprint]) git_cmd.config(['user.email', '*****@*****.**']) git_cmd.config(['user.name', 'debops-keyring-test']) git_cmd.update_environment(GNUPGHOME=os.path.join( tmp_git_repo, 'gpg_tmp_home'), ) tmp_git_file = os.path.join(tmp_git_repo, 'new-file') with open(tmp_git_file, 'w') as tmp_git_fh: tmp_git_fh.write(str(time.time())) git_cmd.add([tmp_git_file]) git_cmd.commit(['--gpg-sign', '--message', 'Signed commit']) debops_keyring = Keyring(keyring_name=tmp_keyring_dir, ) debops_keyring.check_git_commits(tmp_git_repo) # Now make an unsigned commit to ensure that this raises an exception. with open(tmp_git_file, 'w') as tmp_git_fh: tmp_git_fh.write(str(time.time())) git_cmd.add([tmp_git_file]) git_cmd.commit(['--no-gpg-sign', '--message', 'Unsigned commit']) try: debops_keyring.check_git_commits(tmp_git_repo) assert False except Exception as e: if 'OpenPGP signature of commit could not be verified' in str( e) and 'Unsigned commit' in str(e): assert True else: assert False
class gpg(object): """ module to wrap the gnupg library and gpg binary """ def __init__(self, folder_path=None, binary_path=None): # ugly but working if binary_path is None: binary_path = join(project_base, "gpg", "gpg.exe") if not isfile(binary_path): binary_path = join(project_base, 'gpg') if not isfile(binary_path): binary_path = find_executable('gpg') if not isfile(binary_path): raise RuntimeError('gpg not found') self.gpg = GPG( binary_path, # gpgbinary folder_path, # gnupghome verbose=False, options=["--allow-non-selfsigned-uid"]) def get_key(self, fingerprint, private, passphrase): """ returns the key belonging to the fingerprint given. if 'private' is True, the private key is returned. If 'private' is False, the public key will be returned. """ key = self.gpg.export_keys(fingerprint, private, armor=False, passphrase=passphrase) return b64encode(key) def add_keypair(self, public_key, private_key, site, user, passphrase): """ add a keypair into the gpg key database """ try: result1 = self.gpg.import_keys(b64decode(public_key)) result2 = self.gpg.import_keys(b64decode(private_key)) except TypeError as error: getLogger(__name__).critical("add_keypair TypeError " + str(error)) # make sure this is a key _pair_ try: assert result1.fingerprints[0] == result2.fingerprints[0] except (IndexError, AssertionError) as error: getLogger(__name__).exception( 'add_keypair IndexError/AssertionError: ' + str(error)) return None fingerprint = result1.fingerprints[0] if self.is_passphrase_valid(passphrase=passphrase, fingerprint=fingerprint): old_fingerprint = self.get_fingerprint(site, user) if not old_fingerprint: sql = "INSERT INTO keys (site, user, fingerprint) VALUES (?, ?, ?)" database_execute(sql, (site, user, fingerprint)) else: sql = "UPDATE keys SET SITE=? WHERE fingerprint=?" database_execute(sql, (site, old_fingerprint)) if fingerprint != old_fingerprint: getLogger(__name__).warn('updating %s fingerprint to %s' % (user, fingerprint)) return fingerprint else: return None def add_public_key(self, site, user, public_key): """ add a public key into the gpg key database """ try: result1 = self.gpg.import_keys(b64decode(public_key)) fingerprint = result1.fingerprints[0] sql = "INSERT INTO keys (site, user, fingerprint) VALUES (?, ?, ?)" database_execute(sql, (site, user, fingerprint)) return fingerprint except TypeError as error: getLogger(__name__).critical("add_public_key TypeError " + str(error)) except DatabaseError as error: getLogger(__name__).critical("add_public_key DatabaseError " + str(error)) def is_passphrase_valid(self, passphrase, label=None, user=None, fingerprint=None): if not fingerprint: fingerprint = self.get_fingerprint(label, user) sign_result = self.gpg.sign("test", keyid=fingerprint, passphrase=passphrase) return sign_result.data != '' def generate(self, passphrase, site, user): """ Generate a new 2048 bit GPG key and add it to the gpg manager. """ data = self.gpg.gen_key_input(key_length=2048, passphrase=passphrase) dat = self.gpg.gen_key(data) fingerprint = dat.fingerprint sql = "INSERT INTO keys (site, user, fingerprint) VALUES (?, ?, ?);" database_execute(sql, (site, user, fingerprint)) return fingerprint def get_fingerprint(self, site, user): sql = "select fingerprint from keys where site = ? and user = ?" result = database_execute(sql, (site, user)) if not len(result): return None return result[0][0] def has_key(self, site, user): """ Check whether a key is present for a certain site and user """ return self.get_fingerprint(site, user) is None def encrypt(self, data, site, user, armor=False): """ encrypt data for user at site. """ fingerprint = self.get_fingerprint(site, user) cryptdata = self.gpg.encrypt_file(StringIO(data), fingerprint, always_trust=True, armor=armor) return str(cryptdata) def decrypt(self, data, passphrase): """ decrypt data received from site. """ datafile = StringIO(data) result = self.gpg.decrypt_file(datafile, passphrase=passphrase, always_trust=True) return str(result) @staticmethod def add_pkcs7_padding(contents): # Input strings must be a multiple of the segment size 16 bytes in length segment_size = 16 # calculate how much padding is needed old_contents_length = len(contents) next_mult = old_contents_length + (segment_size - old_contents_length % segment_size) getLogger(__name__).debug( 'old contents length %s || new contents length %s' % (old_contents_length, next_mult)) # do the padding padding_byte = chr(next_mult - old_contents_length) contents = contents.ljust(next_mult, padding_byte) return contents @staticmethod def remove_pkcs7_padding(contents): """ Remove PKCS#7 padding bytes >>> gpg.remove_pkcs7_padding('some_content'.ljust(16, chr(4))) 'some_content' >>> gpg.remove_pkcs7_padding('some_content') 'some_content' >>> gpg.remove_pkcs7_padding('') '' :param contents: :return: contents without padding """ if len(contents) < 1: getLogger(__name__).debug( 'contents is empty. No PKCS#7 padding removed') return contents bytes_to_remove = ord(contents[-1]) # will work up to 255 bytes # check if contents have valid PKCS#7 padding if bytes_to_remove > 1 and contents[-2] != contents[-1]: getLogger(__name__).debug('no PKCS#7 padding detected') return contents getLogger(__name__).debug('removing %s bytes of PKCS#7 padding' % bytes_to_remove) return contents[0:(len(contents) - bytes_to_remove)]