def test_cont_get_json_req_with_cipher_mismatch(self): bad_crypto_meta = fake_get_crypto_meta() bad_crypto_meta['cipher'] = 'unknown_cipher' key = fetch_crypto_keys()['container'] pt_etag = 'c6e8196d7f0fff6444b90861fe8d609d' ct_etag = encrypt_and_append_meta(pt_etag, key, crypto_meta=bad_crypto_meta) obj_dict_1 = { "bytes": 16, "last_modified": "2015-04-14T23:33:06.439040", "hash": ct_etag, "name": "testfile", "content_type": "image/jpeg" } listing = [obj_dict_1] fake_body = json.dumps(listing) resp = self._make_cont_get_req(fake_body, 'json') self.assertEqual('500 Internal Error', resp.status) self.assertEqual('Error decrypting container listing', resp.body) self.assertIn("Cipher must be AES_CTR_256", self.decrypter.logger.get_lines_for_level('error')[0])
def _make_response_headers(self, content_length, plaintext_etag, keys, body_key): # helper method to make a typical set of response headers for a GET or # HEAD request cont_key = keys['container'] object_key = keys['object'] body_key_meta = {'key': encrypt(body_key, object_key, FAKE_IV), 'iv': FAKE_IV} body_crypto_meta = fake_get_crypto_meta(body_key=body_key_meta) return HeaderKeyDict({ 'Etag': 'hashOfCiphertext', 'content-type': 'text/plain', 'content-length': content_length, 'X-Object-Sysmeta-Crypto-Etag': '%s; swift_meta=%s' % ( base64.b64encode(encrypt(plaintext_etag, object_key, FAKE_IV)), get_crypto_meta_header()), 'X-Object-Sysmeta-Crypto-Body-Meta': get_crypto_meta_header(body_crypto_meta), 'x-object-transient-sysmeta-crypto-meta-test': base64.b64encode(encrypt('encrypt me', object_key, FAKE_IV)) + ';swift_meta=' + get_crypto_meta_header(), 'x-object-sysmeta-container-update-override-etag': encrypt_and_append_meta('encrypt me, too', cont_key), 'x-object-sysmeta-test': 'do not encrypt me', })
def _make_response_headers(self, content_length, plaintext_etag, keys, body_key): # helper method to make a typical set of response headers for a GET or # HEAD request cont_key = keys['container'] object_key = keys['object'] body_key_meta = { 'key': encrypt(body_key, object_key, FAKE_IV), 'iv': FAKE_IV } body_crypto_meta = fake_get_crypto_meta(body_key=body_key_meta) return HeaderKeyDict({ 'Etag': 'hashOfCiphertext', 'content-type': 'text/plain', 'content-length': content_length, 'X-Object-Sysmeta-Crypto-Etag': '%s; swift_meta=%s' % (base64.b64encode(encrypt(plaintext_etag, object_key, FAKE_IV)), get_crypto_meta_header()), 'X-Object-Sysmeta-Crypto-Body-Meta': get_crypto_meta_header(body_crypto_meta), 'x-object-transient-sysmeta-crypto-meta-test': base64.b64encode(encrypt('encrypt me', object_key, FAKE_IV)) + ';swift_meta=' + get_crypto_meta_header(), 'x-object-sysmeta-container-update-override-etag': encrypt_and_append_meta('encrypt me, too', cont_key), 'x-object-sysmeta-test': 'do not encrypt me', })
def test_GET_cipher_mismatch_for_metadata(self): # Cipher does not match env = {'REQUEST_METHOD': 'GET', CRYPTO_KEY_CALLBACK: fetch_crypto_keys} req = Request.blank('/v1/a/c/o', environ=env) body = 'FAKE APP' key = fetch_crypto_keys()['object'] enc_body = encrypt(body, key, FAKE_IV) bad_crypto_meta = fake_get_crypto_meta() bad_crypto_meta['cipher'] = 'unknown_cipher' hdrs = self._make_response_headers(len(enc_body), md5hex(body), fetch_crypto_keys(), 'not used') hdrs.update({ 'x-object-transient-sysmeta-crypto-meta-test': base64.b64encode(encrypt('encrypt me', key, FAKE_IV)) + ';swift_meta=' + get_crypto_meta_header(crypto_meta=bad_crypto_meta) }) self.app.register('GET', '/v1/a/c/o', HTTPOk, body=enc_body, headers=hdrs) resp = req.get_response(self.decrypter) self.assertEqual('500 Internal Error', resp.status) self.assertEqual('Error decrypting header', resp.body) self.assertIn( 'Error decrypting header X-Object-Transient-Sysmeta-Crypto-Meta-' 'Test', self.decrypter.logger.get_lines_for_level('error')[0])
def test_GET_with_bad_iv_for_user_metadata(self): bad_crypto_meta = fake_get_crypto_meta() bad_crypto_meta['iv'] = 'bad_iv' resp = self._test_bad_crypto_meta_for_user_metadata( 'GET', bad_crypto_meta) self.assertEqual('Error decrypting header', resp.body) self.assertIn('IV must be length 16', self.decrypter.logger.get_lines_for_level('error')[0])
def test_GET_with_bad_iv_for_user_metadata(self): bad_crypto_meta = fake_get_crypto_meta() bad_crypto_meta['iv'] = 'bad_iv' resp = self._test_bad_crypto_meta_for_user_metadata( 'GET', bad_crypto_meta) self.assertEqual('Error decrypting header', resp.body) self.assertIn('IV must be length 16', self.decrypter.logger.get_lines_for_level('error')[0])
def test_GET_with_missing_iv_for_user_metadata(self): bad_crypto_meta = fake_get_crypto_meta() bad_crypto_meta.pop('iv') resp = self._test_bad_crypto_meta_for_user_metadata( 'GET', bad_crypto_meta) self.assertEqual('Error decrypting header', resp.body) self.assertIn('iv', self.decrypter.logger.get_lines_for_level('error')[0])
def test_GET_with_missing_iv_for_user_metadata(self): bad_crypto_meta = fake_get_crypto_meta() bad_crypto_meta.pop('iv') resp = self._test_bad_crypto_meta_for_user_metadata( 'GET', bad_crypto_meta) self.assertEqual('Error decrypting header', resp.body) self.assertIn( 'iv', self.decrypter.logger.get_lines_for_level('error')[0])
def test_cont_get_xml_req_with_cipher_mismatch(self): bad_crypto_meta = fake_get_crypto_meta() bad_crypto_meta['cipher'] = 'unknown_cipher' fake_body = '''<?xml version="1.0" encoding="UTF-8"?> <container name="testc"><object>\ <hash>''' + encrypt_and_append_meta('c6e8196d7f0fff6444b90861fe8d609d', fetch_crypto_keys()['container'], crypto_meta=bad_crypto_meta) + '''\ </hash>\ <content_type>image/jpeg</content_type>\ <name>testfile</name><bytes>16</bytes>\ <last_modified>2015-04-19T02:37:39.601660</last_modified></object>\ </container>''' resp = self._make_cont_get_req(fake_body, 'xml') self.assertEqual('500 Internal Error', resp.status) self.assertEqual('Error decrypting container listing', resp.body) self.assertIn("Cipher must be AES_CTR_256", self.decrypter.logger.get_lines_for_level('error')[0])
def test_GET_cipher_mismatch_for_body(self): # Cipher does not match env = {'REQUEST_METHOD': 'GET', CRYPTO_KEY_CALLBACK: fetch_crypto_keys} req = Request.blank('/v1/a/c/o', environ=env) body = 'FAKE APP' enc_body = encrypt(body, fetch_crypto_keys()['object'], FAKE_IV) bad_crypto_meta = fake_get_crypto_meta() bad_crypto_meta['cipher'] = 'unknown_cipher' hdrs = self._make_response_headers( len(enc_body), md5hex(body), fetch_crypto_keys(), 'not used') hdrs['X-Object-Sysmeta-Crypto-Body-Meta'] = \ get_crypto_meta_header(crypto_meta=bad_crypto_meta) self.app.register( 'GET', '/v1/a/c/o', HTTPOk, body=enc_body, headers=hdrs) resp = req.get_response(self.decrypter) self.assertEqual('500 Internal Error', resp.status) self.assertEqual('Error decrypting object', resp.body) self.assertIn('Error decrypting object', self.decrypter.logger.get_lines_for_level('error')[0]) self.assertIn('Bad crypto meta: Cipher', self.decrypter.logger.get_lines_for_level('error')[0])
def test_cont_get_json_req_with_cipher_mismatch(self): bad_crypto_meta = fake_get_crypto_meta() bad_crypto_meta['cipher'] = 'unknown_cipher' key = fetch_crypto_keys()['container'] pt_etag = 'c6e8196d7f0fff6444b90861fe8d609d' ct_etag = encrypt_and_append_meta(pt_etag, key, crypto_meta=bad_crypto_meta) obj_dict_1 = {"bytes": 16, "last_modified": "2015-04-14T23:33:06.439040", "hash": ct_etag, "name": "testfile", "content_type": "image/jpeg"} listing = [obj_dict_1] fake_body = json.dumps(listing) resp = self._make_cont_get_req(fake_body, 'json') self.assertEqual('500 Internal Error', resp.status) self.assertEqual('Error decrypting container listing', resp.body) self.assertIn("Cipher must be AES_CTR_256", self.decrypter.logger.get_lines_for_level('error')[0])
def test_GET_cipher_mismatch_for_body(self): # Cipher does not match env = {'REQUEST_METHOD': 'GET', CRYPTO_KEY_CALLBACK: fetch_crypto_keys} req = Request.blank('/v1/a/c/o', environ=env) body = 'FAKE APP' enc_body = encrypt(body, fetch_crypto_keys()['object'], FAKE_IV) bad_crypto_meta = fake_get_crypto_meta() bad_crypto_meta['cipher'] = 'unknown_cipher' hdrs = self._make_response_headers(len(enc_body), md5hex(body), fetch_crypto_keys(), 'not used') hdrs['X-Object-Sysmeta-Crypto-Body-Meta'] = \ get_crypto_meta_header(crypto_meta=bad_crypto_meta) self.app.register('GET', '/v1/a/c/o', HTTPOk, body=enc_body, headers=hdrs) resp = req.get_response(self.decrypter) self.assertEqual('500 Internal Error', resp.status) self.assertEqual('Error decrypting object', resp.body) self.assertIn('Error decrypting object', self.decrypter.logger.get_lines_for_level('error')[0]) self.assertIn('Bad crypto meta: Cipher', self.decrypter.logger.get_lines_for_level('error')[0])
def test_GET_cipher_mismatch_for_metadata(self): # Cipher does not match env = {'REQUEST_METHOD': 'GET', CRYPTO_KEY_CALLBACK: fetch_crypto_keys} req = Request.blank('/v1/a/c/o', environ=env) body = 'FAKE APP' key = fetch_crypto_keys()['object'] enc_body = encrypt(body, key, FAKE_IV) bad_crypto_meta = fake_get_crypto_meta() bad_crypto_meta['cipher'] = 'unknown_cipher' hdrs = self._make_response_headers( len(enc_body), md5hex(body), fetch_crypto_keys(), 'not used') hdrs.update({'x-object-transient-sysmeta-crypto-meta-test': base64.b64encode(encrypt('encrypt me', key, FAKE_IV)) + ';swift_meta=' + get_crypto_meta_header(crypto_meta=bad_crypto_meta)}) self.app.register( 'GET', '/v1/a/c/o', HTTPOk, body=enc_body, headers=hdrs) resp = req.get_response(self.decrypter) self.assertEqual('500 Internal Error', resp.status) self.assertEqual('Error decrypting header', resp.body) self.assertIn( 'Error decrypting header X-Object-Transient-Sysmeta-Crypto-Meta-' 'Test', self.decrypter.logger.get_lines_for_level('error')[0])
def test_HEAD_with_bad_iv_for_user_metadata(self): bad_crypto_meta = fake_get_crypto_meta() bad_crypto_meta['iv'] = 'bad_iv' self._test_bad_crypto_meta_for_user_metadata('HEAD', bad_crypto_meta) self.assertIn('IV must be length 16', self.decrypter.logger.get_lines_for_level('error')[0])
def test_HEAD_with_missing_iv_for_user_metadata(self): bad_crypto_meta = fake_get_crypto_meta() bad_crypto_meta.pop('iv') self._test_bad_crypto_meta_for_user_metadata('HEAD', bad_crypto_meta) self.assertIn('iv', self.decrypter.logger.get_lines_for_level('error')[0])
def test_HEAD_with_bad_iv_for_user_metadata(self): bad_crypto_meta = fake_get_crypto_meta() bad_crypto_meta['iv'] = 'bad_iv' self._test_bad_crypto_meta_for_user_metadata('HEAD', bad_crypto_meta) self.assertIn('IV must be length 16', self.decrypter.logger.get_lines_for_level('error')[0])
def test_GET_with_missing_iv_for_object_body(self): bad_crypto_meta = fake_get_crypto_meta(key=os.urandom(32)) bad_crypto_meta.pop('iv') self._test_GET_with_bad_crypto_meta_for_object_body(bad_crypto_meta) self.assertIn("Missing 'iv'", self.decrypter.logger.get_lines_for_level('error')[0])
def test_GET_with_missing_body_key_for_object_body(self): bad_crypto_meta = fake_get_crypto_meta() # no key by default self._test_GET_with_bad_crypto_meta_for_object_body(bad_crypto_meta) self.assertIn("Missing 'body_key'", self.decrypter.logger.get_lines_for_level('error')[0])
def test_GET_with_missing_iv_for_object_body(self): bad_crypto_meta = fake_get_crypto_meta(key=os.urandom(32)) bad_crypto_meta.pop('iv') self._test_GET_with_bad_crypto_meta_for_object_body(bad_crypto_meta) self.assertIn("Missing 'iv'", self.decrypter.logger.get_lines_for_level('error')[0])
def test_HEAD_with_missing_iv_for_user_metadata(self): bad_crypto_meta = fake_get_crypto_meta() bad_crypto_meta.pop('iv') self._test_bad_crypto_meta_for_user_metadata('HEAD', bad_crypto_meta) self.assertIn( 'iv', self.decrypter.logger.get_lines_for_level('error')[0])
def test_HEAD_override_etag_bad_iv(self): bad_crypto_meta = fake_get_crypto_meta() bad_crypto_meta['iv'] = 'bad_iv' resp = self._test_override_etag_bad_meta('HEAD', bad_crypto_meta) self.assertEqual('', resp.body)
def get_crypto_meta_header(crypto_meta=None): if crypto_meta is None: crypto_meta = fake_get_crypto_meta() return dump_crypto_meta(crypto_meta)
def test_GET_with_missing_body_key_for_object_body(self): bad_crypto_meta = fake_get_crypto_meta() # no key by default self._test_GET_with_bad_crypto_meta_for_object_body(bad_crypto_meta) self.assertIn("Missing 'body_key'", self.decrypter.logger.get_lines_for_level('error')[0])
def test_GET_with_bad_body_key_for_object_body(self): body_key_meta = {'key': 'wrapped too short key', 'iv': FAKE_IV} bad_crypto_meta = fake_get_crypto_meta(body_key=body_key_meta) self._test_GET_with_bad_crypto_meta_for_object_body(bad_crypto_meta) self.assertIn('Key must be length 32', self.decrypter.logger.get_lines_for_level('error')[0])
def test_HEAD_override_etag_bad_cipher(self): bad_crypto_meta = fake_get_crypto_meta() bad_crypto_meta['cipher'] = 'unknown cipher' resp = self._test_override_etag_bad_meta('HEAD', bad_crypto_meta) self.assertEqual('', resp.body)
def test_GET_with_bad_iv_for_object_body(self): bad_crypto_meta = fake_get_crypto_meta(key=os.urandom(32)) bad_crypto_meta['iv'] = 'bad_iv' self._test_GET_with_bad_crypto_meta_for_object_body(bad_crypto_meta) self.assertIn('IV must be length 16', self.decrypter.logger.get_lines_for_level('error')[0])
def test_HEAD_override_etag_bad_iv(self): bad_crypto_meta = fake_get_crypto_meta() bad_crypto_meta['iv'] = 'bad_iv' resp = self._test_override_etag_bad_meta('HEAD', bad_crypto_meta) self.assertEqual('', resp.body)
def test_GET_with_bad_body_key_for_object_body(self): body_key_meta = {'key': 'wrapped too short key', 'iv': FAKE_IV} bad_crypto_meta = fake_get_crypto_meta(body_key=body_key_meta) self._test_GET_with_bad_crypto_meta_for_object_body(bad_crypto_meta) self.assertIn('Key must be length 32', self.decrypter.logger.get_lines_for_level('error')[0])
def test_GET_override_etag_bad_cipher(self): bad_crypto_meta = fake_get_crypto_meta() bad_crypto_meta['cipher'] = 'unknown cipher' resp = self._test_override_etag_bad_meta('GET', bad_crypto_meta) self.assertIn('Error decrypting header', resp.body)
def test_GET_override_etag_bad_cipher(self): bad_crypto_meta = fake_get_crypto_meta() bad_crypto_meta['cipher'] = 'unknown cipher' resp = self._test_override_etag_bad_meta('GET', bad_crypto_meta) self.assertIn('Error decrypting header', resp.body)
def test_HEAD_override_etag_bad_cipher(self): bad_crypto_meta = fake_get_crypto_meta() bad_crypto_meta['cipher'] = 'unknown cipher' resp = self._test_override_etag_bad_meta('HEAD', bad_crypto_meta) self.assertEqual('', resp.body)
def get_crypto_meta_header(crypto_meta=None): if crypto_meta is None: crypto_meta = fake_get_crypto_meta() return dump_crypto_meta(crypto_meta)
def test_GET_with_bad_iv_for_object_body(self): bad_crypto_meta = fake_get_crypto_meta(key=os.urandom(32)) bad_crypto_meta['iv'] = 'bad_iv' self._test_GET_with_bad_crypto_meta_for_object_body(bad_crypto_meta) self.assertIn('IV must be length 16', self.decrypter.logger.get_lines_for_level('error')[0])