def test_encode_decode(): key1 = bitjws.PrivateKey() pubkey1 = bitjws.pubkey_to_addr(key1.pubkey.serialize()) key2 = bitjws.PrivateKey() pubkey2 = bitjws.pubkey_to_addr(key2.pubkey.serialize()) ser = bitjws.multisig_sign_serialize([key1, key2]) headers, payload = bitjws.multisig_validate_deserialize(ser) rawpayload = json.loads(ser)['payload'] origpayload = bitjws.base64url_decode(rawpayload.encode('utf8')) keys_found = {pubkey1: False, pubkey2: False} assert len(headers) == 2 for h in headers: assert len(h) == 3 assert h['typ'] == 'JWT' assert h['alg'] == 'CUSTOM-BITCOIN-SIGN' assert h['kid'] in keys_found assert keys_found[h['kid']] == False keys_found[h['kid']] = True assert all(keys_found.values()) assert isinstance(payload.get('exp', ''), (float, int)) assert payload['aud'] is None assert len(payload) == 2 assert payload == json.loads(origpayload.decode('utf8'))
def test_invalid_algorithm(): key1 = bitjws.PrivateKey() # Invalid algorithm name for signing. with pytest.raises(AssertionError): bitjws.sign_serialize(key1, algorithm_name='test') with pytest.raises(AssertionError): bitjws.multisig_sign_serialize([key1], algorithm_name='test') # Invalid algorithm name for verifying. ser = bitjws.sign_serialize(key1) with pytest.raises(AssertionError): bitjws.validate_deserialize(ser, algorithm_name='test') ser = bitjws.multisig_sign_serialize([key1]) with pytest.raises(AssertionError): bitjws.multisig_validate_deserialize(ser, algorithm_name='test')
def test_payload_expired(): key = bitjws.PrivateKey() print(bitjws.privkey_to_wif(key.private_key)) # expire_after must be greater than 0 or None. with pytest.raises(bitjws.jws.InvalidPayload): bitjws.sign_serialize(key, expire_after=0) ser = bitjws.sign_serialize(key, expire_after=0.01) time.sleep(0.02) with pytest.raises(bitjws.jws.InvalidPayload): # payload expired. bitjws.validate_deserialize(ser) # But the signature can still be verified and the msg decoded # if expiration checks are disabled. h, p = bitjws.validate_deserialize(ser, check_expiration=False) assert h and p # Check with multisig. ser = bitjws.multisig_sign_serialize([key], expire_after=0.01) time.sleep(0.02) with pytest.raises(bitjws.jws.InvalidPayload): # payload expired. bitjws.multisig_validate_deserialize(ser)
def test_payload_nojson(): key = bitjws.PrivateKey() # Use a payload that is not JSON encoded. ser = json.loads(bitjws.multisig_sign_serialize([key])) ser['payload'] = bitjws.base64url_encode(b'test').decode('utf8') # Sign the new payload. signdata = '{}.{}'.format(ser['signatures'][0]['protected'], ser['payload']) sig = bitjws.ALGORITHM_AVAILABLE['CUSTOM-BITCOIN-SIGN'].sign( key, signdata) sig64 = bitjws.base64url_encode(sig).decode('utf8') ser['signatures'][0]['signature'] = sig64 serenc = json.dumps(ser) with pytest.raises(bitjws.InvalidMessage): # The new payload was not JSON encoded, so it cannot be # decoded as that. bitjws.multisig_validate_deserialize(serenc) # But we can get its raw value. headers, payload = bitjws.multisig_validate_deserialize(serenc, decode_payload=False) assert len(headers) == 1 assert payload == b'test'
def test_payload_nojson(): key = bitjws.PrivateKey() # Use a payload that is not JSON encoded. ser = json.loads(bitjws.multisig_sign_serialize([key])) ser['payload'] = bitjws.base64url_encode(b'test').decode('utf8') # Sign the new payload. signdata = '{}.{}'.format(ser['signatures'][0]['protected'], ser['payload']) sig = bitjws.ALGORITHM_AVAILABLE['CUSTOM-BITCOIN-SIGN'].sign(key, signdata) sig64 = bitjws.base64url_encode(sig).decode('utf8') ser['signatures'][0]['signature'] = sig64 serenc = json.dumps(ser) with pytest.raises(bitjws.InvalidMessage): # The new payload was not JSON encoded, so it cannot be # decoded as that. bitjws.multisig_validate_deserialize(serenc) # But we can get its raw value. headers, payload = bitjws.multisig_validate_deserialize( serenc, decode_payload=False) assert len(headers) == 1 assert payload == b'test'
def test_multisig_missingkeys(): key = bitjws.PrivateKey() ser = bitjws.multisig_sign_serialize([key]) # This should work. headers, payload = bitjws.multisig_validate_deserialize(ser) assert len(headers) == 1 and payload serobj = json.loads(ser) payload = serobj.pop('payload') ser = json.dumps(serobj) with pytest.raises(bitjws.jws.InvalidMessage): # Key 'payload' is missing. bitjws.multisig_validate_deserialize(ser) serobj['payload'] = payload signatures = serobj.pop('signatures') ser = json.dumps(serobj) with pytest.raises(bitjws.jws.InvalidMessage): # Key 'signatures' is missing. bitjws.multisig_validate_deserialize(ser) serobj['signatures'] = 'hello' ser = json.dumps(serobj) with pytest.raises(bitjws.jws.InvalidMessage): # 'signatures' is not a list. bitjws.multisig_validate_deserialize(ser) del serobj['signatures'] del serobj['payload'] ser = json.dumps(serobj) with pytest.raises(bitjws.jws.InvalidMessage): bitjws.multisig_validate_deserialize(ser) # Remove a key from one of the signatures. serobj['signatures'] = signatures serobj['payload'] = payload sig0 = serobj['signatures'][0].copy() del serobj['signatures'][0]['protected'] ser = json.dumps(serobj) with pytest.raises(bitjws.jws.InvalidMessage): # data['signatures'][0]['protected'] is missing bitjws.multisig_validate_deserialize(ser) serobj['signatures'][0] = sig0.copy() del serobj['signatures'][0]['signature'] ser = json.dumps(serobj) with pytest.raises(bitjws.jws.InvalidMessage): # data['signatures'][0]['signture'] is missing bitjws.multisig_validate_deserialize(ser) # Remove the only signature entry. serobj['signatures'].pop() ser = json.dumps(serobj) with pytest.raises(bitjws.jws.InvalidMessage): # No signatures. bitjws.multisig_validate_deserialize(ser)
def test_multisig_invalidsig(): key = bitjws.PrivateKey() ser = bitjws.multisig_sign_serialize([key]) assert all(bitjws.multisig_validate_deserialize(ser)) serobj = json.loads(ser) dummy = bitjws.base64url_encode(b'a' * 88) serobj['signatures'][0]['signature'] = dummy.decode('utf8') ser = json.dumps(serobj) with pytest.raises(bitjws.jws.InvalidMessage): # Invalid signature length. bitjws.multisig_validate_deserialize(ser)
def test_multisig_partiallyinvalid(): key1 = bitjws.PrivateKey() key2 = bitjws.PrivateKey() key3 = bitjws.PrivateKey() ser = bitjws.multisig_sign_serialize([key1, key2, key3]) assert all(bitjws.multisig_validate_deserialize(ser)) serobj = json.loads(ser) # Swap signatures. sig0 = serobj['signatures'][0]['signature'] sig1 = serobj['signatures'][1]['signature'] sig0, sig1 = sig1, sig0 serobj['signatures'][0]['signature'] = sig0 serobj['signatures'][1]['signature'] = sig1 ser = json.dumps(serobj) headers, payload = bitjws.multisig_validate_deserialize(ser) assert headers is None assert payload is None