def devkey(conn: ServerConnection, devid: str, oldpair: EncryptionPair, newpair: EncryptionPair): '''Replaces the specified device's key stored on the server''' if not utils.validate_uuid(devid): return RetVal(AnsBadRequest, 'Invalid device ID').set_value('status', 400) conn.send_message({ 'Action' : "DEVKEY", 'Data' : { 'Device-ID': devid, 'Old-Key': oldpair.public.as_string(), 'New-Key': newpair.public.as_string() } }) # Receive, decrypt, and return the server challenge response = conn.read_response(server_response) if response.error(): return response if response['Code'] != 100: return wrap_server_error(response) if 'Challenge' not in response['Data'] or 'New-Challenge' not in response['Data']: return RetVal(ServerError, 'server did not return both device challenges') status = oldpair.decrypt(response['Data']['Challenge']) if status.error(): cancel(conn) return RetVal(DecryptionFailure, 'failed to decrypt device challenge for old key') request = { 'Action' : "DEVKEY", 'Data' : { 'Response' : status['data'] } } status = newpair.decrypt(response['Data']['New-Challenge']) if status.error(): cancel(conn) return RetVal(DecryptionFailure, 'failed to decrypt device challenge for new key') request['Data']['New-Response'] = status['data'] conn.send_message(request) response = conn.read_response(None) if response.error(): return response if response['Code'] == 200: return RetVal() return wrap_server_error(response)
def device(conn: ServerConnection, devid: str, devpair: EncryptionPair) -> RetVal: '''Completes the login process by submitting device ID and its session string.''' if not utils.validate_uuid(devid): return RetVal(AnsBadRequest, 'Invalid device ID').set_value('status', 400) conn.send_message({ 'Action' : "DEVICE", 'Data' : { 'Device-ID' : devid, 'Device-Key' : devpair.public.as_string() } }) # Receive, decrypt, and return the server challenge response = conn.read_response(server_response) if response.error(): return response if response['Code'] != 100: return wrap_server_error(response) if 'Challenge' not in response['Data']: return RetVal(ServerError, 'server did not return a device challenge') status = devpair.decrypt(response['Data']['Challenge']) if status.error(): cancel(conn) return RetVal(DecryptionFailure, 'failed to decrypt device challenge') conn.send_message({ 'Action' : "DEVICE", 'Data' : { 'Device-ID' : devid, 'Device-Key' : devpair.public.as_string(), 'Response' : status['data'] } }) response = conn.read_response(None) if response.error(): return response if response['Code'] == 200: return RetVal() return wrap_server_error(response)
def test_devkey(): '''Tests the DEVKEY command''' dbconn = setup_test() dbdata = init_server(dbconn) conn = ServerConnection() assert conn.connect('localhost', 2001), "Connection to server at localhost:2001 failed" # password is 'SandstoneAgendaTricycle' pwhash = '$argon2id$v=19$m=65536,t=2,p=1$ew5lqHA5z38za+257DmnTA$0LWVrI2r7XCq' \ 'dcCYkJLok65qussSyhN5TTZP+OTgzEI' devid = '22222222-2222-2222-2222-222222222222' devpair = EncryptionPair( CryptoString(r'CURVE25519:@X~msiMmBq0nsNnn0%~x{M|NU_{?<Wj)cYybdh&Z'), CryptoString(r'CURVE25519:W30{oJ?w~NBbj{F8Ag4~<bcWy6_uQ{i{X?NDq4^l')) dbdata['pwhash'] = pwhash dbdata['devid'] = devid dbdata['devpair'] = devpair # Most of the code which was originally written for this test is needed for other tests # because commands like PREREG require being logged in as the administrator. Both of these # functions still perform all the necessary tests that were originally done here. regcode_admin(dbdata, conn) login_admin(dbdata, conn) newdevpair = EncryptionPair( CryptoString(r'CURVE25519:F0HjK;dB8tr<*2UkaHP?e1-tWAohWJ?IP+oP@o@C'), CryptoString(r'CURVE25519:|Cs(42=7FEwCoKG|5fVPC%MR6gD)_{h}}?ah%cIn')) conn.send_message({ 'Action': 'DEVKEY', 'Data': { 'Device-ID': devid, 'Old-Key': dbdata['devpair'].get_public_key(), 'New-Key': newdevpair.get_public_key() } }) response = conn.read_response(None) assert response != 100 and response['Status'] == 'CONTINUE' and \ 'Challenge' in response['Data'] and 'New-Challenge' in response['Data'], \ "test_devkey(): server failed to return new and old key challenge" msg = {'Action': "DEVKEY", 'Data': {}} status = devpair.decrypt(response['Data']['Challenge']) assert not status.error( ), 'login_devkey(): failed to decrypt device challenge for old key' msg['Data']['Response'] = status['data'] status = newdevpair.decrypt(response['Data']['New-Challenge']) assert not status.error( ), 'login_devkey(): failed to decrypt device challenge for new key' msg['Data']['New-Response'] = status['data'] conn.send_message(msg) response = conn.read_response(None) assert response['Code'] == 200 and response['Status'] == 'OK', \ 'Server challenge-response phase failed' conn.send_message({'Action': "QUIT"})