예제 #1
0
class reqPGP(object):
    def __init__(self, path=None):
        self.gpg = GPG(gpgbinary=('../gpg.exe' if osName == 'nt' else 'gpg'))
        if not path:
            try:
                self.path = environ["HOME"] + '/'
            except KeyError:
                self.path = environ["HOMEPATH"] + '\\'
        else:
            if path[-1] != '\\' and osName == 'nt':
                path += '\\'
            elif path[-1] != '/' and osName == 'posix':
                path += '/'
            self.path = path

    def genKey(self, account, passphrase):
        input_data = self.gpg.gen_key_input(name_email=account,
                                            passphrase=passphrase)
        self.gpg.gen_key(input_data)

    def encryptFile(self, account, data):
        encryptedData = str(self.gpg.encrypt(data, account))
        with open(self.path + '.' + account + '.req', 'w') as f:
            f.write(encryptedData)

    def decryptFile(self, account, passphrase):
        with open(self.path + '.' + account + '.req', 'rb') as f:
            decryptedData = str(self.gpg.decrypt_file(f,
                                                      passphrase=passphrase))
        return decryptedData

    def deleteKey(self, keyId):
        self.gpg.delete_keys(keyId, True)
        self.gpg.delete_keys(keyId)
예제 #2
0
class reqPGP(object):
    def __init__(self, path=None):
        self.gpg = GPG(gpgbinary=('../gpg.exe' if osName == 'nt' else 'gpg'))
        if not path:
            try:
                self.path = environ["HOME"] + '/'
            except KeyError:
                self.path = environ["HOMEPATH"] + '\\'
        else:
            if path[-1] != '\\' and osName == 'nt':
                path += '\\'
            elif path[-1] != '/' and osName == 'posix':
                path += '/'
            self.path = path
            

    def genKey(self, account, passphrase):
        input_data = self.gpg.gen_key_input(
            name_email=account,
            passphrase=passphrase)
        self.gpg.gen_key(input_data)

    def encryptFile(self, account, data):
        encryptedData = str(self.gpg.encrypt(data, account))
        with open(self.path + '.' + account + '.req', 'w') as f:
            f.write(encryptedData)

    def decryptFile(self, account, passphrase):
        with open(self.path + '.' + account + '.req', 'rb') as f:
            decryptedData = str(self.gpg.decrypt_file(f, passphrase=passphrase))
        return decryptedData
    
    def deleteKey(self, keyId):
        self.gpg.delete_keys(keyId, True)
        self.gpg.delete_keys(keyId)
예제 #3
0
 def delete(self):
     """
     Remove any keys for this address.
     """
     gpg = GPG(gnupghome=GNUPG_HOME)
     for key in gpg.list_keys():
         if self.address in addresses_for_key(gpg, key):
             gpg.delete_keys(key["fingerprint"], True)
             gpg.delete_keys(key["fingerprint"])
     super(Address, self).delete()
예제 #4
0
 def delete(self):
     """
     Remove any keys for this address.
     """
     gpg = GPG(gnupghome=GNUPG_HOME)
     for key in gpg.list_keys():
         if self.address in addresses_for_key(gpg, key):
             gpg.delete_keys(key["fingerprint"], True)
             gpg.delete_keys(key["fingerprint"])
     super(Address, self).delete()
예제 #5
0
		def delete(self):
			"""
			remove any keys for this address
			"""
			from email_extras.utils import addresses_for_key
			gpg = GPG(gnupghome=GNUPG_HOME)
			for key in gpg.list_keys():
				if self.address in addresses_for_key(gpg, key):
					gpg.delete_keys(key["fingerprint"], True)
					gpg.delete_keys(key["fingerprint"])
			super(Address, self).delete()
예제 #6
0
def key_edit(key, password, path_to_user_folder):

	try:
		gpg = GPG()
		gpg.delete_keys(key, True, passphrase=password)
		gpg.delete_keys(key)
		key_data = open(path_to_user_folder+'/main/gpg_private_key.asc').read()
		new_key = gpg.import_keys(key_data)
		new_key = new_key.results[0]['fingerprint']
		gpg.trust_keys(new_key, "TRUST_ULTIMATE")
		system('echo RELOADAGENT | gpg-connect-agent')
		copy2(path_to_user_folder+'/main/gpg_private_key.asc', path_to_user_folder+'/user_data/gpg_private_key.asc')
		return new_key

	except:
		msg = bot.send_message(message.chat.id, 'Произошла ошибка.', reply_markup = types.ReplyKeyboardRemove(selective=False))
		del_mess(msg, bot, 6)
		return key
예제 #7
0
파일: openpgp.py 프로젝트: elijh/keymanager
class TempGPGWrapper(object):
    """
    A context manager that wraps a temporary GPG keyring which only contains
    the keys given at object creation.
    """

    def __init__(self, keys=None, gpgbinary=None):
        """
        Create an empty temporary keyring and import any given C{keys} into
        it.

        :param keys: OpenPGP key, or list of.
        :type keys: OpenPGPKey or list of OpenPGPKeys
        :param gpgbinary: Name for GnuPG binary executable.
        :type gpgbinary: C{str}
        """
        self._gpg = None
        self._gpgbinary = gpgbinary
        if not keys:
            keys = list()
        if not isinstance(keys, list):
            keys = [keys]
        self._keys = keys
        for key in keys:
            leap_assert_type(key, OpenPGPKey)

    def __enter__(self):
        """
        Build and return a GPG keyring containing the keys given on
        object creation.

        :return: A GPG instance containing the keys given on object creation.
        :rtype: gnupg.GPG
        """
        self._build_keyring()
        return self._gpg

    def __exit__(self, exc_type, exc_value, traceback):
        """
        Ensure the gpg is properly destroyed.
        """
        # TODO handle exceptions and log here
        self._destroy_keyring()

    def _build_keyring(self):
        """
        Create a GPG keyring containing the keys given on object creation.

        :return: A GPG instance containing the keys given on object creation.
        :rtype: gnupg.GPG
        """
        privkeys = [key for key in self._keys if key and key.private is True]
        publkeys = [key for key in self._keys if key and key.private is False]
        # here we filter out public keys that have a correspondent
        # private key in the list because the private key_data by
        # itself is enough to also have the public key in the keyring,
        # and we want to count the keys afterwards.

        privfps = map(lambda privkey: privkey.fingerprint, privkeys)
        publkeys = filter(
            lambda pubkey: pubkey.fingerprint not in privfps, publkeys)

        listkeys = lambda: self._gpg.list_keys()
        listsecretkeys = lambda: self._gpg.list_keys(secret=True)

        self._gpg = GPG(binary=self._gpgbinary,
                        homedir=tempfile.mkdtemp())
        leap_assert(len(listkeys()) is 0, 'Keyring not empty.')

        # import keys into the keyring:
        # concatenating ascii-armored keys, which is correctly
        # understood by GPG.

        self._gpg.import_keys("".join(
            [x.key_data for x in publkeys + privkeys]))

        # assert the number of keys in the keyring
        leap_assert(
            len(listkeys()) == len(publkeys) + len(privkeys),
            'Wrong number of public keys in keyring: %d, should be %d)' %
            (len(listkeys()), len(publkeys) + len(privkeys)))
        leap_assert(
            len(listsecretkeys()) == len(privkeys),
            'Wrong number of private keys in keyring: %d, should be %d)' %
            (len(listsecretkeys()), len(privkeys)))

    def _destroy_keyring(self):
        """
        Securely erase the keyring.
        """
        # TODO: implement some kind of wiping of data or a more
        # secure way that
        # does not write to disk.

        try:
            for secret in [True, False]:
                for key in self._gpg.list_keys(secret=secret):
                    self._gpg.delete_keys(
                        key['fingerprint'],
                        secret=secret)
            leap_assert(len(self._gpg.list_keys()) is 0, 'Keyring not empty!')

        except:
            raise

        finally:
            leap_assert(self._gpg.homedir != os.path.expanduser('~/.gnupg'),
                        "watch out! Tried to remove default gnupg home!")
            shutil.rmtree(self._gpg.homedir)
예제 #8
0
class Test(unittest.TestCase):
    '''Unit test cases for signing envelopes from the Learning Registry'''
    def __init__(self, methodName="runTest"):
        
        self.gpgbin="/usr/local/bin/gpg"
        self.gnupgHome = os.path.expanduser(os.path.join("~", ".gnupg"))
        self.gpg = GPG(gpgbinary=self.gpgbin, gnupghome=self.gnupgHome)
        
        unittest.TestCase.__init__(self, methodName)
        
        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"]
        
        
        
    def setUp(self):
        now = time.localtime()
        now = calendar.timegm(now)
        self.goodEmail = "signTest-{0}@learningregistry.org".format(now)
        self.goodRealName = "Autogenerated Sign Test"
        self.goodpassphrase = "supersecret"
        
        input = self.gpg.gen_key_input(name_real=self.goodRealName, name_email=self.goodEmail, passphrase=self.goodpassphrase)
        self.goodPrivateKey = self.gpg.gen_key(input)
        
        privateKeyAvailable = False
        privateKeys = self.gpg.list_keys(secret=True)
        for skey in privateKeys:
            if skey["keyid"] == self.goodPrivateKey.fingerprint:
                privateKeyAvailable = True
                self.privateKeyInfo = skey
                break
            if skey["fingerprint"] == self.goodPrivateKey.fingerprint:
                privateKeyAvailable = True
                self.privateKeyInfo = skey
                break
        
        assert privateKeyAvailable == True, "Could not locate generated Private Key"
        
        self.goodkeyid = self.privateKeyInfo["keyid"]
        
        self.goodowner = self.privateKeyInfo["uids"][0]
        
        
        self.badkeyid = "XXXXXXXXXXXXXXXX"
        self.badpassphrase = "bad passphrase"
        
        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 &amp; 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.sampleJSON_strip = '''{"keys": ["United States--Description and travel.", "eng"], "TOS": {"submission_attribution": "unidentified", "submission_TOS": "http://example.com/tos/unknown"}, "payload_placement": "inline", "active": true, "resource_locator": "http://hdl.loc.gov/loc.gdc/lhbtn.12281", "doc_type": "resource_data", "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 &amp; 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      ", "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_schema": ["oai_dc"], "doc_version": "0.10.0", "submitter": "NSDL 2 LR Data Pump"}'''
        self.sampleJSON_strip_normal = '''{"keys": ["United States--Description and travel.", "eng"], "TOS": {"submission_attribution": "unidentified", "submission_TOS": "http://example.com/tos/unknown"}, "payload_placement": "inline", "active": "true", "resource_locator": "http://hdl.loc.gov/loc.gdc/lhbtn.12281", "doc_type": "resource_data", "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 &amp; 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      ", "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_schema": ["oai_dc"], "doc_version": "0.10.0", "submitter": "NSDL 2 LR Data Pump"}''' 
        self.sampleJSON_strip_normal_bencode = '''d3:TOSd14:submission_TOS30:http://example.com/tos/unknown22:submission_attribution12:unidentifiede6:active4:true8:doc_type13:resource_data11:doc_version6:0.10.04:keysl38:United States--Description and travel.3:enge17:payload_placement6:inline14:payload_schemal6:oai_dce22:payload_schema_locator90:http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd13:resource_data968:<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 &amp; 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      18:resource_data_type8:metadata16:resource_locator38:http://hdl.loc.gov/loc.gdc/lhbtn.122819:submitter19:NSDL 2 LR Data Pump14:submitter_type5:agente'''
        self.sampleJSON_sha256 = '''ef1b3b63adc663602c7a3c7595951b2761b34f5f6490ea1acee3df0fd97db03c'''
        
        self.sampleKeyLocations = [
                                   "http://example.com/mykey",
                                   "http://example2.com/mykey"
                                   ]
       
        
        self.signatureTemplate = '{{"key_location": [{0}], "key_owner": "'+self.goodowner+'", "signing_method": "LR-PGP.1.0", "signature": "{1}"}}'

    def tearDown(self):
        self.gpg.delete_keys([self.goodPrivateKey.fingerprint, ], secret=True)
        self.gpg.delete_keys([self.goodPrivateKey.fingerprint, ], secret=False)
        pass
        
    def testMissingPrivateKey(self):
        
        def missingKey():
            try:
                sign = Sign_0_21(self.badkeyid)
            except UnknownKeyException as e:
                assert e.keyid == self.badkeyid, "keyid in exception doesn't match key passed to sign."
                raise e
            
        self.assertRaises(UnknownKeyException, missingKey)

    def testPresentPrivateKey(self):
        sign = Sign_0_21(self.goodkeyid)
        assert sign.privateKeyID == self.goodkeyid 
        
    def testStrip(self):
        origJson = json.loads(self.sampleJSON)
        benchmark = json.loads(self.sampleJSON_strip)
        
        signer = Sign_0_21(self.goodkeyid)        
        stripJson = signer._stripEnvelope(origJson)
        assert benchmark == stripJson
        
    def testStripNormal(self):
        origJson = json.loads(self.sampleJSON)
        benchmark = json.loads(self.sampleJSON_strip_normal)
        
        signer = Sign_0_21(self.goodkeyid)        
        stripJson = signer._stripEnvelope(origJson)
        normalJson = signer._bnormal(stripJson)
        assert benchmark == normalJson
    
    def testStripNormalBencode(self):
        origJson = json.loads(self.sampleJSON)
        benchmark = self.sampleJSON_strip_normal_bencode
        
        signer = Sign_0_21(self.goodkeyid)        
        stripJson = signer._stripEnvelope(origJson)
        normalJson = signer._bnormal(stripJson)
        bencodeJson = signer._buildCanonicalString(normalJson)
        assert benchmark == bencodeJson
    
    def testStripNormalBencodeHash(self):
        origJson = json.loads(self.sampleJSON)
        benchmark = self.sampleJSON_sha256
        
        signer = Sign_0_21(self.goodkeyid)        
        stripJson = signer._stripEnvelope(origJson)
        normalJson = signer._bnormal(stripJson)
        bencodeJson = signer._buildCanonicalString(normalJson)
        hash = signer._hash(bencodeJson)
        assert benchmark == hash
        
    def testGetMessage(self):
        origJson = json.loads(self.sampleJSON)
        benchmark = self.sampleJSON_sha256
        
        signer = Sign_0_21(self.goodkeyid)
        message = signer.get_message(origJson)
        assert benchmark == message
    
    def testPrivateKeyOwner(self):
        benchmark = self.goodowner
        signer = Sign_0_21(self.goodkeyid)
        assert benchmark == signer._get_privatekey_owner()
    
    def testSigBlock(self):
        origJson = json.loads(self.sampleJSON)
        arbitrarySigdata = "ABCDEF0123456789-abcdef"
        arbitraryKeyLoc = self.sampleKeyLocations
        
        keyloc = ",".join(map(lambda x: '"{0}"'.format(x), arbitraryKeyLoc))
        benchmark = json.loads(self.signatureTemplate.format(keyloc, arbitrarySigdata))
        
        signer = Sign_0_21(self.goodkeyid, passphrase=self.goodpassphrase, publicKeyLocations=arbitraryKeyLoc)
        assert benchmark == signer._get_sig_block(arbitrarySigdata)
     
    def testSign(self):
        origJson = json.loads(self.sampleJSON)
        arbitraryKeyLoc = self.sampleKeyLocations
        
        signer = Sign_0_21(self.goodkeyid, passphrase=self.goodpassphrase, publicKeyLocations=arbitraryKeyLoc)
        signed = signer.sign(origJson)
        
        assert signed.has_key("digital_signature")
        
        sig = signed["digital_signature"]
        assert sig.has_key("signature")
        assert sig["signature"] != None and len(sig["signature"]) > 0
    
    def testSignUnicode(self):
        if self.testDataDir == None:
            log.info("Skipping test, test data directory not set.")
            return
        
        import codecs
        
        fileName = "2011-02-28Metadata1004.json"
        unsigned = json.load(codecs.open(os.path.join(self.testDataDir, fileName), "r", "utf-8-sig"))
        
        arbitraryKeyLoc = self.sampleKeyLocations
        
        signer = Sign_0_21(self.goodkeyid, passphrase=self.goodpassphrase, publicKeyLocations=arbitraryKeyLoc)
        signed = signer.sign(unsigned)
        
        assert signed.has_key("digital_signature")
        
        sig = signed["digital_signature"]
        assert sig.has_key("signature")
        assert sig["signature"] != None and len(sig["signature"]) > 0
        
    def testSignLRTestData(self):
        if self.testDataDir == None:
            log.info("Skipping test, test data directory not set.")
            return
        
        import codecs
        
        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"))
        
            arbitraryKeyLoc = self.sampleKeyLocations
            
            signer = Sign_0_21(self.goodkeyid, passphrase=self.goodpassphrase, publicKeyLocations=arbitraryKeyLoc)
            signed = signer.sign(unsigned)
            
            assert signed.has_key("digital_signature")
            
            sig = signed["digital_signature"]
            assert sig.has_key("signature")
            assert sig["signature"] != None and len(sig["signature"]) > 0
예제 #9
0
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 &amp; 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"
예제 #10
0
class TempGPGWrapper(object):
    """
    A context manager that wraps a temporary GPG keyring which only contains
    the keys given at object creation.
    """
    log = Logger()

    def __init__(self, keys=None, gpgbinary=None):
        """
        Create an empty temporary keyring and import any given C{keys} into
        it.

        :param keys: OpenPGP key, or list of.
        :type keys: OpenPGPKey or list of OpenPGPKeys
        :param gpgbinary: Name for GnuPG binary executable.
        :type gpgbinary: C{str}
        """
        self._gpg = None
        self._gpgbinary = gpgbinary
        if not keys:
            keys = list()
        if not isinstance(keys, list):
            keys = [keys]
        self._keys = keys

    def __enter__(self):
        """
        Build and return a GPG keyring containing the keys given on
        object creation.

        :return: A GPG instance containing the keys given on object creation.
        :rtype: gnupg.GPG
        """
        self._build_keyring()
        return self._gpg

    def __exit__(self, exc_type, exc_value, traceback):
        """
        Ensure the gpg is properly destroyed.
        """
        # TODO handle exceptions and log here
        self._destroy_keyring()

    def _build_keyring(self):
        """
        Create a GPG keyring containing the keys given on object creation.

        :return: A GPG instance containing the keys given on object creation.
        :rtype: gnupg.GPG
        """
        privkeys = [key for key in self._keys if key and key.private is True]
        publkeys = [key for key in self._keys if key and key.private is False]
        # here we filter out public keys that have a correspondent
        # private key in the list because the private key_data by
        # itself is enough to also have the public key in the keyring,
        # and we want to count the keys afterwards.

        privfps = map(lambda privkey: privkey.fingerprint, privkeys)
        publkeys = filter(
            lambda pubkey: pubkey.fingerprint not in privfps, publkeys)

        listkeys = lambda: self._gpg.list_keys()
        listsecretkeys = lambda: self._gpg.list_keys(secret=True)

        try:
            self._gpg = GPG(binary=self._gpgbinary,
                            homedir=tempfile.mkdtemp())
        except TypeError:
            # compat-mode with python-gnupg until windows
            # support is fixed in gnupg-ng
            self._gpg = GPG(gpgbinary=self._gpgbinary,
                            gnupghome=tempfile.mkdtemp(),
                            options=[])

        leap_assert(len(listkeys()) is 0, 'Keyring not empty.')

        # import keys into the keyring:
        # concatenating ascii-armored keys, which is correctly
        # understood by GPG.

        self._gpg.import_keys("".join(
            [x.key_data for x in publkeys + privkeys]))

        # assert the number of keys in the keyring
        leap_assert(
            len(listkeys()) == len(publkeys) + len(privkeys),
            'Wrong number of public keys in keyring: %d, should be %d)' %
            (len(listkeys()), len(publkeys) + len(privkeys)))
        leap_assert(
            len(listsecretkeys()) == len(privkeys),
            'Wrong number of private keys in keyring: %d, should be %d)' %
            (len(listsecretkeys()), len(privkeys)))

    def _destroy_keyring(self):
        """
        Securely erase the keyring.
        """
        # TODO: implement some kind of wiping of data or a more
        # secure way that
        # does not write to disk.

        try:
            for secret in [True, False]:
                for key in self._gpg.list_keys(secret=secret):
                    self._gpg.delete_keys(
                        key['fingerprint'],
                        secret=secret)
            leap_assert(len(self._gpg.list_keys()) is 0, 'Keyring not empty!')

        except:
            raise

        finally:
            try:
                homedir = self._gpg.homedir
            except AttributeError:
                homedir = self._gpg.gnupghome
            leap_assert(homedir != os.path.expanduser('~/.gnupg'),
                        "watch out! Tried to remove default gnupg home!")
            # TODO some windows debug ....
            homedir = os.path.normpath(homedir).replace("\\", "/")
            homedir = str(homedir.replace("c:/", "c://"))
            if platform.system() == "Windows":
                self.log.error("BUG! Not erasing folder in Windows")
                return
            shutil.rmtree(homedir)
예제 #11
0
class Test(unittest.TestCase):
    '''Unit test cases for signing envelopes from the Learning Registry'''
    def __init__(self, methodName="runTest"):

        self.gpgbin = "gpg"
        self.gnupgHome = os.path.expanduser(
            os.path.abspath(os.path.join("..", "gnupg_home")))

        try:
            os.makedirs(self.gnupghome)
        except:
            pass

        self.gpg = None

        unittest.TestCase.__init__(self, methodName)

        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"]

    def setUp(self):
        now = time.localtime()
        now = calendar.timegm(now)
        self.goodEmail = "signTest-{0}@learningregistry.org".format(now)
        self.goodRealName = "Autogenerated Sign Test"
        self.goodpassphrase = "supersecret"

        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)

        input = self.gpg.gen_key_input(name_real=self.goodRealName,
                                       name_email=self.goodEmail,
                                       passphrase=self.goodpassphrase)
        self.goodPrivateKey = self.gpg.gen_key(input)

        privateKeyAvailable = False
        privateKeys = self.gpg.list_keys(secret=True)
        for skey in privateKeys:
            if skey["keyid"] == self.goodPrivateKey.fingerprint:
                privateKeyAvailable = True
                self.privateKeyInfo = skey
                break
            if skey["fingerprint"] == self.goodPrivateKey.fingerprint:
                privateKeyAvailable = True
                self.privateKeyInfo = skey
                break

        assert privateKeyAvailable == True, "Could not locate generated Private Key"

        self.goodkeyid = self.privateKeyInfo["keyid"]

        self.goodowner = self.privateKeyInfo["uids"][0]

        self.badkeyid = "XXXXXXXXXXXXXXXX"
        self.badpassphrase = "bad passphrase"

        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 &amp; 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.sampleJSON__0_23_0 = '''
            {
                "_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 &amp; 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"],
                "identity":{
                    "submitter_type":"agent",
                    "submitter":"NSDL 2 LR Data Pump"
                },
                "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",
                "payload_schema":["oai_dc"],
                "node_timestamp":"2011-03-14 13:36:04.617999",
                "doc_version":"0.23.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.sampleJSON__0_51_0 = '''
            {
                "_id":"00e3f67232e743b6bc2a079bd98ff55a",
                "_rev":"1-8163d32f6cc9996f2b7228d8b5db7962",
                "doc_type":"resource_data",
                "update_timestamp":"2014-04-01 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 &amp; 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"],
                "identity":{
                    "submitter_type":"agent",
                    "submitter":"NSDL 2 LR Data Pump"
                },
                "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",
                "payload_schema":["oai_dc"],
                "node_timestamp":"2014-04-01 13:32:04.617999",
                "doc_version":"0.51.0",
                "create_timestamp":"2014-04-01 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.sampleJSON_no_coercion = '''
            {
                "_id":"00e3f67232e743b6bc2a079bd98ff55a",
                "_rev":"1-8163d32f6cc9996f2b7228d8b5db7962",
                "doc_type":"resource_data",
                "update_timestamp":"2011-03-14 13:36:04.617999",
                "resource_data": {
                    "name": "Test coersion",
                    "nullable": null,
                    "booleanT": true,
                    "booleanF": false
                },
                "keys":["United States--Description and travel.","eng"],
                "identity":{
                    "submitter_type":"agent",
                    "submitter":"NSDL 2 LR Data Pump"
                },
                "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",
                "payload_schema":["oai_dc"],
                "node_timestamp":"2011-03-14 13:36:04.617999",
                "doc_version":"0.23.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.sampleJSON_lossy_sha256 = [
            '''
            {
                "_id":"00e3f67232e743b6bc2a079bd98ff55a",
                "_rev":"1-8163d32f6cc9996f2b7228d8b5db7962",
                "doc_type":"resource_data",
                "update_timestamp":"2011-03-14 13:36:04.617999",
                "resource_data": {
                    "name": "Test Lossy"
                    "integer": 1
                },
                "keys":["United States--Description and travel.","eng"],
                "identity":{
                    "submitter_type":"agent",
                    "submitter":"NSDL 2 LR Data Pump"
                },
                "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",
                "payload_schema":["oai_dc"],
                "node_timestamp":"2011-03-14 13:36:04.617999",
                "doc_version":"0.23.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"
                }
            }
            ''', '''
            {
                "_id":"00e3f67232e743b6bc2a079bd98ff55a",
                "_rev":"1-8163d32f6cc9996f2b7228d8b5db7962",
                "doc_type":"resource_data",
                "update_timestamp":"2011-03-14 13:36:04.617999",
                "resource_data": {
                    "name": "Test Lossy"
                    "float": 1.1
                },
                "keys":["United States--Description and travel.","eng"],
                "identity":{
                    "submitter_type":"agent",
                    "submitter":"NSDL 2 LR Data Pump"
                },
                "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",
                "payload_schema":["oai_dc"],
                "node_timestamp":"2011-03-14 13:36:04.617999",
                "doc_version":"0.23.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"
                }
            }
            ''', '''
            {
                "_id":"00e3f67232e743b6bc2a079bd98ff55a",
                "_rev":"1-8163d32f6cc9996f2b7228d8b5db7962",
                "doc_type":"resource_data",
                "update_timestamp":"2011-03-14 13:36:04.617999",
                "resource_data": {
                    "name": "Test Lossy"
                    "max_int": 9007199254740990
                },
                "keys":["United States--Description and travel.","eng"],
                "identity":{
                    "submitter_type":"agent",
                    "submitter":"NSDL 2 LR Data Pump"
                },
                "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",
                "payload_schema":["oai_dc"],
                "node_timestamp":"2011-03-14 13:36:04.617999",
                "doc_version":"0.23.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"
                }
            }
            ''', '''
            {
                "_id":"00e3f67232e743b6bc2a079bd98ff55a",
                "_rev":"1-8163d32f6cc9996f2b7228d8b5db7962",
                "doc_type":"resource_data",
                "update_timestamp":"2011-03-14 13:36:04.617999",
                "resource_data": {
                    "name": "Test Lossy"
                    "min_int": -9007199254740990
                },
                "keys":["United States--Description and travel.","eng"],
                "identity":{
                    "submitter_type":"agent",
                    "submitter":"NSDL 2 LR Data Pump"
                },
                "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",
                "payload_schema":["oai_dc"],
                "node_timestamp":"2011-03-14 13:36:04.617999",
                "doc_version":"0.23.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.sampleJSON_strip = '''{"keys": ["United States--Description and travel.", "eng"], "TOS": {"submission_attribution": "unidentified", "submission_TOS": "http://example.com/tos/unknown"}, "payload_placement": "inline", "active": true, "resource_locator": "http://hdl.loc.gov/loc.gdc/lhbtn.12281", "doc_type": "resource_data", "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 &amp; 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      ", "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_schema": ["oai_dc"], "doc_version": "0.10.0", "submitter": "NSDL 2 LR Data Pump"}'''
        self.sampleJSON_strip_normal = '''{"keys": ["United States--Description and travel.", "eng"], "TOS": {"submission_attribution": "unidentified", "submission_TOS": "http://example.com/tos/unknown"}, "payload_placement": "inline", "active": "true", "resource_locator": "http://hdl.loc.gov/loc.gdc/lhbtn.12281", "doc_type": "resource_data", "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 &amp; 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      ", "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_schema": ["oai_dc"], "doc_version": "0.10.0", "submitter": "NSDL 2 LR Data Pump"}'''
        self.sampleJSON_strip_normal_bencode = '''d3:TOSd14:submission_TOS30:http://example.com/tos/unknown22:submission_attribution12:unidentifiede6:active4:true8:doc_type13:resource_data11:doc_version6:0.10.04:keysl38:United States--Description and travel.3:enge17:payload_placement6:inline14:payload_schemal6:oai_dce22:payload_schema_locator90:http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd13:resource_data968:<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 &amp; 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      18:resource_data_type8:metadata16:resource_locator38:http://hdl.loc.gov/loc.gdc/lhbtn.122819:submitter19:NSDL 2 LR Data Pump14:submitter_type5:agente'''
        self.sampleJSON_sha256 = '''ef1b3b63adc663602c7a3c7595951b2761b34f5f6490ea1acee3df0fd97db03c'''

        self.sampleKeyLocations = [
            "http://example.com/mykey", "http://example2.com/mykey"
        ]

        self.signatureTemplate = '{{"key_location": [{0}], "key_owner": "' + self.goodowner + '", "signing_method": "LR-PGP.1.0", "signature": "{1}"}}'

    def tearDown(self):
        self.gpg.delete_keys([
            self.goodPrivateKey.fingerprint,
        ], secret=True)
        self.gpg.delete_keys([
            self.goodPrivateKey.fingerprint,
        ], secret=False)
        pass

    def testMissingPrivateKey(self):
        def missingKey():
            try:
                sign = Sign_0_21(self.badkeyid,
                                 gnupgHome=self.gnupgHome,
                                 gpgbin=self.gpgbin)
            except UnknownKeyException as e:
                assert e.keyid == self.badkeyid, "keyid in exception doesn't match key passed to sign."
                raise e

        self.assertRaises(UnknownKeyException, missingKey)

    def testPresentPrivateKey(self):
        sign = Sign_0_21(self.goodkeyid,
                         gnupgHome=self.gnupgHome,
                         gpgbin=self.gpgbin)
        assert sign.privateKeyID == self.goodkeyid

    def testStrip(self):
        origJson = json.loads(self.sampleJSON)
        benchmark = json.loads(self.sampleJSON_strip)

        signer = Sign_0_21(self.goodkeyid,
                           gnupgHome=self.gnupgHome,
                           gpgbin=self.gpgbin)
        stripJson = signer._stripEnvelope(origJson)
        assert benchmark == stripJson

    def testStripNormal(self):
        origJson = json.loads(self.sampleJSON)
        benchmark = json.loads(self.sampleJSON_strip_normal)

        signer = Sign_0_21(self.goodkeyid,
                           gnupgHome=self.gnupgHome,
                           gpgbin=self.gpgbin)
        stripJson = signer._stripEnvelope(origJson)
        normalJson = signer._bnormal(stripJson)
        assert benchmark == normalJson

    def testStripNormalBencode(self):
        origJson = json.loads(self.sampleJSON)
        benchmark = self.sampleJSON_strip_normal_bencode

        signer = Sign_0_21(self.goodkeyid,
                           gnupgHome=self.gnupgHome,
                           gpgbin=self.gpgbin)
        stripJson = signer._stripEnvelope(origJson)
        normalJson = signer._bnormal(stripJson)
        bencodeJson = signer._buildCanonicalString(normalJson)
        assert benchmark == bencodeJson

    def testStripNormalBencodeHash(self):
        origJson = json.loads(self.sampleJSON)
        benchmark = self.sampleJSON_sha256

        signer = Sign_0_21(self.goodkeyid,
                           gnupgHome=self.gnupgHome,
                           gpgbin=self.gpgbin)
        stripJson = signer._stripEnvelope(origJson)
        normalJson = signer._bnormal(stripJson)
        bencodeJson = signer._buildCanonicalString(normalJson)
        hashed = signer._hash(bencodeJson)
        assert benchmark == hashed

    def testKnownLossyHash(self):
        for idx, lossyJSON in enumerate(self.sampleJSON_lossy_sha256):
            origJson = json.loads(self.sampleJSON)

            signer = Sign_0_21(self.goodkeyid,
                               gnupgHome=self.gnupgHome,
                               gpgbin=self.gpgbin)
            stripJson = signer._stripEnvelope(origJson)
            normalJson = signer._bnormal(stripJson)
            bencodeJson = signer._buildCanonicalString(normalJson)
            hashed = signer._hash(bencodeJson)

            if idx > 0:
                assert prev_hashed == hashed, "Hashes should match - algorithm is lossy"
                assert prev_bencodeJson == bencodeJson, "Bencode strings should match - algorithm is lossy"

            prev_bencodeJson = bencodeJson
            prev_hashed = hashed

    def testGetMessage(self):
        origJson = json.loads(self.sampleJSON)
        benchmark = self.sampleJSON_sha256

        signer = Sign_0_21(self.goodkeyid,
                           gnupgHome=self.gnupgHome,
                           gpgbin=self.gpgbin)
        message = signer.get_message(origJson)
        assert benchmark == message

    def testPrivateKeyOwner(self):
        benchmark = self.goodowner
        signer = Sign_0_21(self.goodkeyid,
                           gnupgHome=self.gnupgHome,
                           gpgbin=self.gpgbin)
        assert benchmark == signer._get_privatekey_owner()

    def testSigBlock(self):
        origJson = json.loads(self.sampleJSON)
        arbitrarySigdata = "ABCDEF0123456789-abcdef"
        arbitraryKeyLoc = self.sampleKeyLocations

        keyloc = ",".join(['"{0}"'.format(x) for x in arbitraryKeyLoc])
        benchmark = json.loads(
            self.signatureTemplate.format(keyloc, arbitrarySigdata))

        signer = Sign_0_21(self.goodkeyid,
                           passphrase=self.goodpassphrase,
                           publicKeyLocations=arbitraryKeyLoc,
                           gnupgHome=self.gnupgHome,
                           gpgbin=self.gpgbin)
        assert benchmark == signer._get_sig_block(arbitrarySigdata)

    def testSignNoEnvelopeCoercion(self):
        origJson = json.loads(self.sampleJSON_no_coercion)
        arbitraryKeyLoc = self.sampleKeyLocations

        assert origJson["resource_data"]["nullable"] == None, "Expected null"
        assert origJson["resource_data"]["booleanT"] == True, "Expected true"
        assert origJson["resource_data"]["booleanF"] == False, "Expected false"

        signer = Sign_0_21(self.goodkeyid,
                           passphrase=self.goodpassphrase,
                           publicKeyLocations=arbitraryKeyLoc,
                           gnupgHome=self.gnupgHome,
                           gpgbin=self.gpgbin)
        signed = signer.sign(origJson)

        assert "digital_signature" in signed
        assert origJson["resource_data"]["nullable"] == None, "Expected null"
        assert origJson["resource_data"]["booleanT"] == True, "Expected true"
        assert origJson["resource_data"]["booleanF"] == False, "Expected false"

    def testSign_0_10__no_passthru(self):
        origJson = json.loads(self.sampleJSON)
        arbitraryKeyLoc = self.sampleKeyLocations

        signer = Sign_0_21(self.goodkeyid,
                           passphrase=self.goodpassphrase,
                           publicKeyLocations=arbitraryKeyLoc,
                           gnupgHome=self.gnupgHome,
                           gpgbin=self.gpgbin)
        signed = signer.sign(origJson)

        assert "digital_signature" in signed

        sig = signed["digital_signature"]
        assert "signature" in sig
        assert sig["signature"] != None and len(sig["signature"]) > 0

    def test_Sign__0_10__passthru(self):
        origJson = json.loads(self.sampleJSON)
        arbitraryKeyLoc = self.sampleKeyLocations

        signer = Sign_0_21(self.goodkeyid,
                           passphrase=self.goodpassphrase,
                           publicKeyLocations=arbitraryKeyLoc,
                           sign_everything=False,
                           gnupgHome=self.gnupgHome,
                           gpgbin=self.gpgbin)
        signed = signer.sign(origJson)

        assert "digital_signature" not in signed

        # sig = signed["digital_signature"]
        # assert sig.has_key("signature")
        # assert sig["signature"] != None and len(sig["signature"]) > 0

    def test_Sign__0_23__passthru(self):
        origJson = json.loads(self.sampleJSON__0_23_0)
        arbitraryKeyLoc = self.sampleKeyLocations

        signer = Sign_0_23(self.goodkeyid,
                           passphrase=self.goodpassphrase,
                           publicKeyLocations=arbitraryKeyLoc,
                           sign_everything=False,
                           gnupgHome=self.gnupgHome,
                           gpgbin=self.gpgbin)
        signed = signer.sign(origJson)

        assert "digital_signature" in signed
        sig = signed["digital_signature"]
        assert "signature" in sig
        assert sig["signature"] != None and len(sig["signature"]) > 0

    def test_Sign__0_23__no_passthru(self):
        origJson = json.loads(self.sampleJSON__0_23_0)
        arbitraryKeyLoc = self.sampleKeyLocations

        signer = Sign_0_23(self.goodkeyid,
                           passphrase=self.goodpassphrase,
                           publicKeyLocations=arbitraryKeyLoc,
                           sign_everything=True,
                           gnupgHome=self.gnupgHome,
                           gpgbin=self.gpgbin)
        signed = signer.sign(origJson)

        assert "digital_signature" in signed
        sig = signed["digital_signature"]
        assert "signature" in sig
        assert sig["signature"] != None and len(sig["signature"]) > 0

    def test_Sign__0_51__no_passthru(self):
        origJson = json.loads(self.sampleJSON__0_51_0)
        arbitraryKeyLoc = self.sampleKeyLocations

        signer = Sign_0_51(self.goodkeyid,
                           passphrase=self.goodpassphrase,
                           publicKeyLocations=arbitraryKeyLoc,
                           sign_everything=True,
                           gnupgHome=self.gnupgHome,
                           gpgbin=self.gpgbin)
        signed = signer.sign(origJson)

        assert "digital_signature" in signed
        sig = signed["digital_signature"]
        assert "signature" in sig
        assert sig["signature"] != None and len(sig["signature"]) > 0

    def testSignUnicode(self):
        if self.testDataUnicode == None:
            log.info("Skipping test, unicode test data file not set.")
            return

        import codecs

        # fileName = "2011-02-28Metadata1004.json"
        # unsigned = json.load(codecs.open(os.path.join(self.testDataDir, fileName), "r", "utf-8-sig"))
        unsigned = json.load(
            codecs.open(self.testDataUnicode, "r", "utf-8-sig"))

        arbitraryKeyLoc = self.sampleKeyLocations

        signer = Sign_0_21(self.goodkeyid,
                           passphrase=self.goodpassphrase,
                           publicKeyLocations=arbitraryKeyLoc,
                           gnupgHome=self.gnupgHome,
                           gpgbin=self.gpgbin)
        signed = signer.sign(unsigned)

        assert "digital_signature" in signed

        sig = signed["digital_signature"]
        assert "signature" in sig
        assert sig["signature"] != None and len(sig["signature"]) > 0

    def testSignLRTestData(self):
        if self.testDataDir == None:
            log.info("Skipping test, test data directory not set.")
            return

        import codecs

        # 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"))

                arbitraryKeyLoc = self.sampleKeyLocations

                signer = Sign_0_21(self.goodkeyid,
                                   passphrase=self.goodpassphrase,
                                   publicKeyLocations=arbitraryKeyLoc,
                                   gnupgHome=self.gnupgHome,
                                   gpgbin=self.gpgbin)
                signed = signer.sign(unsigned)

                assert "digital_signature" in signed

                sig = signed["digital_signature"]
                assert "signature" in sig
                assert sig["signature"] != None and len(sig["signature"]) > 0
예제 #12
0
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 &amp; 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"
예제 #13
0
def rm_key(key, password):
	gpg = GPG()
	gpg.delete_keys(key, True, passphrase=password)
	gpg.delete_keys(key)
	system('echo RELOADAGENT | gpg-connect-agent')