def testGetHacked(self, promiscuous_client): seed = libnacl.randombytes(libnacl.crypto_sign_SEEDBYTES) vk, sk, did, body = eddsa.genDidHistory(seed, signer=0, numSigners=2, method="fake") vk = h.bytesToStr64u(vk) signature = eddsa.signResource(body, sk) headers = {"Signature": 'signer="{0}"'.format(signature)} response = promiscuous_client.simulate_post(HISTORY_BASE_PATH, body=body, headers=headers) assert response.status == falcon.HTTP_201 seed = libnacl.randombytes(libnacl.crypto_sign_SEEDBYTES) vk2, sk2, did2, body2 = eddsa.genDidHistory(seed, signer=0, numSigners=2) vk2 = h.bytesToStr64u(vk2) body2 = json.loads(body2) body2["id"] = did body2 = json.dumps(body2).encode() signature2 = eddsa.signResource(body2, sk2) headers2 = {"Signature": 'signer="{0}"'.format(signature2)} response = promiscuous_client.simulate_post(HISTORY_BASE_PATH, body=body2, headers=headers2) assert response.status == falcon.HTTP_201 response = promiscuous_client.simulate_get("{}/{}".format( EVENTS_BASE_PATH, did)) exp_result = [ [{ "event": json.loads(body2.decode()), "signatures": { "signer": signature2 } }], [{ "event": json.loads(body.decode()), "signatures": { "signer": signature } }], ] assert response.status == falcon.HTTP_200 assert json.loads(response.content) == exp_result
def generate64uKeys(seed=None): """ :param seed: optional seed value for libnacl.crypto_sign_seed_keypair() :return: base64 url-file safe key string (vk, sk) """ vk, sk = generateByteKeys(seed) return bytesToStr64u(vk), bytesToStr64u(sk)
def testGetAll(self, race_client): seed = libnacl.randombytes(libnacl.crypto_sign_SEEDBYTES) vk, sk, did, body = eddsa.genDidHistory(seed, signer=0, numSigners=2) vk = h.bytesToStr64u(vk) signature = eddsa.signResource(body, sk) headers = {"Signature": 'signer="{0}"'.format(signature)} race_client.simulate_post(HISTORY_BASE_PATH, body=body, headers=headers) seed = libnacl.randombytes(libnacl.crypto_sign_SEEDBYTES) vk2, sk2, did2, body2 = eddsa.genDidHistory(seed, signer=0, numSigners=2) vk2 = h.bytesToStr64u(vk2) signature2 = eddsa.signResource(body2, sk2) headers2 = {"Signature": 'signer="{0}"'.format(signature2)} race_client.simulate_post(HISTORY_BASE_PATH, body=body2, headers=headers2) response = race_client.simulate_get(EVENTS_BASE_PATH) exp_result = { "data": [[[{ "event": json.loads(body.decode()), "signatures": { "signer": signature } }]], [[{ "event": json.loads(body2.decode()), "signatures": { "signer": signature2 } }]]] } response_data = json.loads(response.content) assert response.status == falcon.HTTP_200 assert len(response_data["data"]) == 2 # response_data order is unreliable # make sure that each history exists only once in response for result in exp_result['data']: matches = 0 for data in response_data['data']: if data == result: matches += 1 assert matches == 1
def testHackerRevocation(client): # Make sure that a hacker can't revoke someone elses keys. seed = libnacl.randombytes(libnacl.crypto_sign_SEEDBYTES) vk, sk, did, body = eddsa.genDidHistory(seed, signer=0, numSigners=2) vk = h.bytesToStr64u(vk) headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format(eddsa.signResource(body, sk), eddsa.signResource(body, sk)) } # send inception event client.simulate_post(HISTORY_BASE_PATH, body=body, headers=headers) # Add did to database seed = libnacl.randombytes(libnacl.crypto_sign_SEEDBYTES) hacked_vk, hacked_sk = eddsa.generateByteKeys(seed) hacked_vk = h.bytesToStr64u(hacked_vk) body = json.loads(body) body['changed'] = "2000-01-01T00:00:02+00:00" body['signer'] = 5 body['signers'].append(hacked_vk) body['signers'].append(hacked_vk) body['signers'].append(hacked_vk) body['signers'].append(None) headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format( eddsa.signResource( json.dumps(body, ensure_ascii=False).encode(), hacked_sk), eddsa.signResource( json.dumps(body, ensure_ascii=False).encode(), hacked_sk)) } exp_result = { "title": "Authorization Error", "description": "Could not validate the request signature for rotation field. Unverifiable signature." } verifyRequest(client.simulate_put, "{0}/{1}".format(HISTORY_BASE_PATH, did), body, headers, exp_result=exp_result, exp_status=falcon.HTTP_401)
def testVerify64u(): resource = "message" vk, sk = ecdsa.generateByteKeys() vk = bytesToStr64u(vk) signature = ecdsa.signResource(resource.encode(), sk) assert ecdsa.verify64u(signature, resource, vk)
def testGet(self, race_client): seed = libnacl.randombytes(libnacl.crypto_sign_SEEDBYTES) vk, sk, did, body = eddsa.genDidHistory(seed, signer=0, numSigners=2) vk = h.bytesToStr64u(vk) signature = eddsa.signResource(body, sk) headers = {"Signature": 'signer="{0}"'.format(signature)} race_client.simulate_post(HISTORY_BASE_PATH, body=body, headers=headers) response = race_client.simulate_get("{}/{}".format( EVENTS_BASE_PATH, did)) exp_result = [[{ "event": json.loads(body.decode()), "signatures": { "signer": signature } }]] assert response.status == falcon.HTTP_200 assert json.loads(response.content) == exp_result
def testPutUnchangedSignerField(client): # send updated history with new public key but unchanged signer field seed = libnacl.randombytes(libnacl.crypto_sign_SEEDBYTES) vk, sk, did, body = eddsa.genDidHistory(seed, signer=0, numSigners=2) vk = h.bytesToStr64u(vk) headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format(eddsa.signResource(body, sk), eddsa.signResource(body, sk)) } # send inception event client.simulate_post(HISTORY_BASE_PATH, body=body, headers=headers) # Add did to database body = json.loads(body) body['changed'] = "2000-01-01T00:00:02+00:00" body['signer'] = 1 body['signers'].append(vk) headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format( eddsa.signResource( json.dumps(body, ensure_ascii=False).encode(), sk), eddsa.signResource( json.dumps(body, ensure_ascii=False).encode(), sk)) } # rotate once client.simulate_put("{0}/{1}".format(HISTORY_BASE_PATH, did), body=json.dumps(body).encode(), headers=headers) # Add new pre-rotated key but don't update signer field body['signers'].append(vk) body['changed'] = "2000-01-01T00:00:03+00:00" headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format( eddsa.signResource( json.dumps(body, ensure_ascii=False).encode(), sk), eddsa.signResource( json.dumps(body, ensure_ascii=False).encode(), sk)) } exp_result = { "title": "Validation Error", "description": "signer field must be one greater than previous." } verifyRequest(client.simulate_put, "{0}/{1}".format(HISTORY_BASE_PATH, did), body, headers, exp_result=exp_result, exp_status=falcon.HTTP_400)
def signResource(resource, sk): """ Produce a signature for resource :param resource: byte string message to be signed :param sk: byte string signing key :return: base64 url-file safe string """ sig = libnacl.crypto_sign(resource, sk) sig = sig[:libnacl.crypto_sign_BYTES] return bytesToStr64u(sig)
def genDidHistory(seed=None, changed="2000-01-01T00:00:00+00:00", signer=0, numSigners=3, method="dad"): # seed = libnacl.randombytes(libnacl.crypto_sign_SEEDBYTES) vk, sk = generateByteKeys(seed) did = makeDid(vk, method) body = { "id": did, "changed": changed, "signer": signer, "signers": [] } for i in range(0, numSigners): body['signers'].append(bytesToStr64u(vk)) return vk, sk, did, json.dumps(body, ensure_ascii=False).encode()
def testValidateHistoryModelUpdate(): data = { "id": DID, "signer": 0, "changed": "2000-01-01T00:00:01+00:00", "signers": [ "NOf6ZghvGNbFc_wr3CC0tKZHz1qWAR4lD5aM-i0zSjw=", "NOf6ZghvGNbFc_wr3CC0tKZHz1qWAR4lD5aM-i0zSjw=" ] } sigs = [didery.crypto.eddsa.signResource(json.dumps(data).encode(), SK)] history = { "history": data, "signatures": sigs, } test_data = [history] test_model = ValidatedHistoryModel(test_data) seed = b'\x92[\xcb\xf4\xee5+\xcf\xd4b*%/\xabw8\xd4d\xa2\xf8\xad\xa7U\x19,\xcfS\x12\xa6l\xba"' vk, sk, did, body = didery.crypto.eddsa.genDidHistory(seed, signer=0, numSigners=2) vk = h.bytesToStr64u(vk) data2 = json.loads(body) data2["id"] = DID sigs2 = [didery.crypto.eddsa.signResource(json.dumps(data2).encode(), sk)] history2 = {"history": data2, "signatures": sigs2} test_data = [history2] test_model.update(0, history2) assert test_model.data == test_data
def testGetAllMultiEvent(self, race_client): seed = libnacl.randombytes(libnacl.crypto_sign_SEEDBYTES) vk, sk, did, body = eddsa.genDidHistory(seed, signer=0, numSigners=2) vk = h.bytesToStr64u(vk) signature = eddsa.signResource(body, sk) headers = {"Signature": 'signer="{0}"'.format(signature)} race_client.simulate_post(HISTORY_BASE_PATH, body=body, headers=headers) body2 = json.loads(body) body2['changed'] = "2000-01-01T00:00:01+00:00" body2['signer'] = 1 body2['signers'].append(vk) body2 = json.dumps(body2).encode() signer = eddsa.signResource(body2, sk) rotation = eddsa.signResource(body2, sk) headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format(signer, rotation) } response = race_client.simulate_put("{}/{}".format( HISTORY_BASE_PATH, did), body=body2, headers=headers) assert response.status == falcon.HTTP_200 seed = libnacl.randombytes(libnacl.crypto_sign_SEEDBYTES) vk3, sk3, did3, body3 = eddsa.genDidHistory(seed, signer=0, numSigners=2) vk3 = h.bytesToStr64u(vk3) signature3 = eddsa.signResource(body3, sk3) headers3 = {"Signature": 'signer="{0}"'.format(signature3)} race_client.simulate_post(HISTORY_BASE_PATH, body=body3, headers=headers3) response = race_client.simulate_get(EVENTS_BASE_PATH) exp_result = { "data": [[[{ "event": json.loads(body2.decode()), "signatures": { "signer": signer, "rotation": rotation } }, { "event": json.loads(body.decode()), "signatures": { "signer": signature } }]], [[{ "event": json.loads(body3.decode()), "signatures": { "signer": signature3 } }]]] } response_data = json.loads(response.content) assert response.status == falcon.HTTP_200 assert len(response_data["data"]) == 2 # response_data order is unreliable # make sure that each history exists only once in response for result in exp_result['data']: matches = 0 for data in response_data['data']: if data == result: matches += 1 assert matches == 1