static void handshakestate_check_errors(void) { NoiseHandshakeState *state; NoiseProtocolId id; /* NULL parameters in various positions */ compare(noise_handshakestate_has_local_keypair(0), 0); compare(noise_handshakestate_has_remote_public_key(0), 0); compare(noise_handshakestate_needs_remote_public_key(0), 0); compare(noise_handshakestate_needs_pre_shared_key(0), 0); compare(noise_handshakestate_has_pre_shared_key(0), 0); compare(noise_handshakestate_get_role(0), 0); compare(noise_handshakestate_get_action(0), NOISE_ACTION_NONE); compare(noise_handshakestate_start(0), NOISE_ERROR_INVALID_PARAM); /* If the id/name/role is unknown, state parameter should be set to NULL */ memset(&id, 0, sizeof(id)); state = (NoiseHandshakeState *)8; compare(noise_handshakestate_new_by_id(&state, &id, NOISE_ROLE_INITIATOR), NOISE_ERROR_UNKNOWN_ID); verify(state == NULL); state = (NoiseHandshakeState *)8; compare(noise_handshakestate_new_by_name(&state, 0, NOISE_ROLE_RESPONDER), NOISE_ERROR_INVALID_PARAM); verify(state == NULL); state = (NoiseHandshakeState *)8; compare(noise_handshakestate_new_by_name (&state, "Noise_XX_25519_ChaChaPony_BLAKE2s", NOISE_ROLE_INITIATOR), NOISE_ERROR_UNKNOWN_NAME); state = (NoiseHandshakeState *)8; compare(noise_handshakestate_new_by_name (&state, "Noise_XX_25519_ChaChaPoly_BLAKE2s", NOISE_DH_CURVE25519), NOISE_ERROR_INVALID_PARAM); verify(state == NULL); id.prefix_id = NOISE_PREFIX_STANDARD; id.pattern_id = NOISE_PATTERN_XX; id.dh_id = NOISE_DH_CURVE25519; id.cipher_id = NOISE_CIPHER_CHACHAPOLY; id.hash_id = NOISE_HASH_BLAKE2s; state = (NoiseHandshakeState *)8; compare(noise_handshakestate_new_by_id(&state, &id, NOISE_DH_CURVE25519), NOISE_ERROR_INVALID_PARAM); verify(state == NULL); }
int main(int argc, char *argv[]) { NoiseHandshakeState *handshake = 0; NoiseCipherState *send_cipher = 0; NoiseCipherState *recv_cipher = 0; EchoProtocolId id; NoiseProtocolId nid; NoiseBuffer mbuf; size_t message_size; int fd; int err; int ok = 1; int action; /* Parse the command-line options */ if (!parse_options(argc, argv)) return 1; /* Change into the key directory and load all of the keys we'll need */ if (chdir(key_dir) < 0) { perror(key_dir); return 1; } if (!echo_load_private_key ("server_key_25519", server_key_25519, sizeof(server_key_25519))) { return 1; } if (!echo_load_private_key ("server_key_448", server_key_448, sizeof(server_key_448))) { return 1; } if (!echo_load_public_key ("client_key_25519.pub", client_key_25519, sizeof(client_key_25519))) { return 1; } if (!echo_load_public_key ("client_key_448.pub", client_key_448, sizeof(client_key_448))) { return 1; } if (!echo_load_public_key("psk", psk, sizeof(psk))) { return 1; } /* Accept an incoming connection */ fd = echo_accept(port); /* Read the echo protocol identifier sent by the client */ if (ok && !echo_recv_exact(fd, (uint8_t *)&id, sizeof(id))) { fprintf(stderr, "Did not receive the echo protocol identifier\n"); ok = 0; } /* Convert the echo protocol identifier into a Noise protocol identifier */ if (ok && !echo_to_noise_protocol_id(&nid, &id)) { fprintf(stderr, "Unknown echo protocol identifier\n"); ok = 0; } /* Create a HandshakeState object to manage the server's handshake */ if (ok) { err = noise_handshakestate_new_by_id (&handshake, &nid, NOISE_ROLE_RESPONDER); if (err != NOISE_ERROR_NONE) { noise_perror("create handshake", err); ok = 0; } } /* Set all keys that are needed by the client's requested echo protocol */ if (ok) { if (!initialize_handshake(handshake, &nid, &id, sizeof(id))) { ok = 0; } } /* Start the handshake */ if (ok) { err = noise_handshakestate_start(handshake); if (err != NOISE_ERROR_NONE) { noise_perror("start handshake", err); ok = 0; } } /* Run the handshake until we run out of things to read or write */ while (ok) { action = noise_handshakestate_get_action(handshake); if (action == NOISE_ACTION_WRITE_MESSAGE) { /* Write the next handshake message with a zero-length payload */ noise_buffer_set_output(mbuf, message + 2, sizeof(message) - 2); err = noise_handshakestate_write_message(handshake, &mbuf, NULL); if (err != NOISE_ERROR_NONE) { noise_perror("write handshake", err); ok = 0; break; } message[0] = (uint8_t)(mbuf.size >> 8); message[1] = (uint8_t)mbuf.size; if (!echo_send(fd, message, mbuf.size + 2)) { ok = 0; break; } } else if (action == NOISE_ACTION_READ_MESSAGE) {
/* Check the behaviour of a specific handshake protocol. These tests check whether the initiator and responder can talk to each other via the protocol but they do not check for correct bytes on the wire. Wire checks are done by the separate vector tests. */ static void check_handshake_protocol(const char *name) { NoiseHandshakeState *initiator; NoiseHandshakeState *responder; NoiseHandshakeState *send; NoiseHandshakeState *recv; NoiseProtocolId id, id2; NoiseDHState *dh; const uint8_t *pattern; NoisePatternFlags_t init_flags; NoisePatternFlags_t resp_flags; uint8_t message[4096]; uint8_t payload[23]; NoiseBuffer mbuf; NoiseBuffer pbuf; int action; int index; /* Set the name of this test for error reporting */ data_name = name; /* Convert the name into a protocol identifier and look up the pattern */ compare(noise_protocol_name_to_id(&id, name, strlen(name)), NOISE_ERROR_NONE); pattern = noise_pattern_lookup(id.pattern_id); verify(pattern != 0); init_flags = ((NoisePatternFlags_t)(pattern[0])) | (((NoisePatternFlags_t)(pattern[1])) << 8); resp_flags = noise_pattern_reverse_flags(init_flags); /* Create two objects for the initiator and responder, one by name and the other by identifier. */ compare(noise_handshakestate_new_by_name (&initiator, name, NOISE_ROLE_INITIATOR), NOISE_ERROR_NONE); compare(noise_handshakestate_new_by_id (&responder, &id, NOISE_ROLE_RESPONDER), NOISE_ERROR_NONE); /* Check that the "needs" functions report results consistent with the requirements of the protocol */ compare(noise_handshakestate_needs_local_keypair(initiator), (init_flags & NOISE_PAT_FLAG_LOCAL_STATIC) != 0); compare(noise_handshakestate_needs_remote_public_key(initiator), (init_flags & NOISE_PAT_FLAG_REMOTE_REQUIRED) != 0); compare(noise_handshakestate_needs_pre_shared_key(initiator), id.prefix_id == NOISE_PREFIX_PSK); compare(noise_handshakestate_needs_local_keypair(responder), (resp_flags & NOISE_PAT_FLAG_LOCAL_STATIC) != 0); compare(noise_handshakestate_needs_remote_public_key(responder), (resp_flags & NOISE_PAT_FLAG_REMOTE_REQUIRED) != 0); compare(noise_handshakestate_needs_pre_shared_key(responder), id.prefix_id == NOISE_PREFIX_PSK); /* Check other properties */ compare(noise_handshakestate_get_role(initiator), NOISE_ROLE_INITIATOR); compare(noise_handshakestate_get_role(responder), NOISE_ROLE_RESPONDER); memset(&id2, 0xAA, sizeof(id2)); compare(noise_handshakestate_get_protocol_id(initiator, &id2), NOISE_ERROR_NONE); verify(!memcmp(&id, &id2, sizeof(id))); memset(&id2, 0x66, sizeof(id2)); compare(noise_handshakestate_get_protocol_id(responder, &id2), NOISE_ERROR_NONE); verify(!memcmp(&id, &id2, sizeof(id))); /* Specify a fixed prologue on each end */ compare(noise_handshakestate_set_prologue(initiator, "Hello", 5), NOISE_ERROR_NONE); compare(noise_handshakestate_set_prologue(responder, "Hello", 5), NOISE_ERROR_NONE); /* Set the keys that are needed on each end */ compare(noise_handshakestate_has_local_keypair(initiator), 0); if (noise_handshakestate_needs_local_keypair(initiator)) { compare(noise_handshakestate_start(initiator), NOISE_ERROR_LOCAL_KEY_REQUIRED); dh = noise_handshakestate_get_local_keypair_dh(initiator); if (noise_dhstate_get_dh_id(dh) == NOISE_DH_CURVE25519) { compare(noise_dhstate_set_keypair_private (dh, init_private_25519, sizeof(init_private_25519)), NOISE_ERROR_NONE); } else { compare(noise_dhstate_set_keypair_private (dh, init_private_448, sizeof(init_private_448)), NOISE_ERROR_NONE); } compare(noise_handshakestate_has_local_keypair(initiator), 1); } else { dh = noise_handshakestate_get_local_keypair_dh(initiator); verify(dh == 0); } compare(noise_handshakestate_has_remote_public_key(initiator), 0); if (noise_handshakestate_needs_remote_public_key(initiator)) { compare(noise_handshakestate_start(initiator), NOISE_ERROR_REMOTE_KEY_REQUIRED); dh = noise_handshakestate_get_remote_public_key_dh(initiator); if (noise_dhstate_get_dh_id(dh) == NOISE_DH_CURVE25519) { compare(noise_dhstate_set_public_key (dh, resp_public_25519, sizeof(resp_public_25519)), NOISE_ERROR_NONE); } else { compare(noise_dhstate_set_public_key (dh, resp_public_448, sizeof(resp_public_448)), NOISE_ERROR_NONE); } compare(noise_handshakestate_has_remote_public_key(initiator), 1); } else { dh = noise_handshakestate_get_remote_public_key_dh(initiator); if ((init_flags & NOISE_PAT_FLAG_REMOTE_STATIC) != 0) verify(dh != 0); else verify(dh == 0); } compare(noise_handshakestate_has_local_keypair(responder), 0); if (noise_handshakestate_needs_local_keypair(responder)) { compare(noise_handshakestate_start(responder), NOISE_ERROR_LOCAL_KEY_REQUIRED); dh = noise_handshakestate_get_local_keypair_dh(responder); if (noise_dhstate_get_dh_id(dh) == NOISE_DH_CURVE25519) { compare(noise_dhstate_set_keypair_private (dh, resp_private_25519, sizeof(resp_private_25519)), NOISE_ERROR_NONE); } else { compare(noise_dhstate_set_keypair_private (dh, resp_private_448, sizeof(resp_private_448)), NOISE_ERROR_NONE); } compare(noise_handshakestate_has_local_keypair(responder), 1); } else { dh = noise_handshakestate_get_local_keypair_dh(responder); verify(dh == 0); } compare(noise_handshakestate_has_remote_public_key(responder), 0); if (noise_handshakestate_needs_remote_public_key(responder)) { compare(noise_handshakestate_start(responder), NOISE_ERROR_REMOTE_KEY_REQUIRED); dh = noise_handshakestate_get_remote_public_key_dh(responder); if (noise_dhstate_get_dh_id(dh) == NOISE_DH_CURVE25519) { compare(noise_dhstate_set_public_key (dh, init_public_25519, sizeof(init_public_25519)), NOISE_ERROR_NONE); } else { compare(noise_dhstate_set_public_key (dh, init_public_448, sizeof(init_public_448)), NOISE_ERROR_NONE); } compare(noise_handshakestate_has_remote_public_key(responder), 1); } else { dh = noise_handshakestate_get_remote_public_key_dh(responder); if ((init_flags & NOISE_PAT_FLAG_LOCAL_STATIC) != 0) verify(dh != 0); else verify(dh == 0); } compare(noise_handshakestate_has_pre_shared_key(initiator), 0); if (noise_handshakestate_needs_pre_shared_key(initiator)) { compare(noise_handshakestate_start(initiator), NOISE_ERROR_PSK_REQUIRED); compare(noise_handshakestate_set_pre_shared_key (initiator, psk, sizeof(psk)), NOISE_ERROR_NONE); compare(noise_handshakestate_has_pre_shared_key(initiator), 1); } else { compare(noise_handshakestate_set_pre_shared_key (initiator, psk, sizeof(psk)), NOISE_ERROR_NOT_APPLICABLE); } compare(noise_handshakestate_has_pre_shared_key(responder), 0); if (noise_handshakestate_needs_pre_shared_key(responder)) { compare(noise_handshakestate_start(responder), NOISE_ERROR_PSK_REQUIRED); compare(noise_handshakestate_set_pre_shared_key (responder, psk, sizeof(psk)), NOISE_ERROR_NONE); compare(noise_handshakestate_has_pre_shared_key(responder), 1); } else { compare(noise_handshakestate_set_pre_shared_key (initiator, psk, sizeof(psk)), NOISE_ERROR_NOT_APPLICABLE); } /* Start the handshake running */ compare(noise_handshakestate_start(initiator), NOISE_ERROR_NONE); compare(noise_handshakestate_start(responder), NOISE_ERROR_NONE); /* Starting the handshake again should fail (already running) */ compare(noise_handshakestate_start(initiator), NOISE_ERROR_INVALID_STATE); compare(noise_handshakestate_start(responder), NOISE_ERROR_INVALID_STATE); /* Run the two handshakes in parallel while something to read/write */ memset(payload, 0xAA, sizeof(payload)); for (;;) { /* Which direction for this message? */ action = noise_handshakestate_get_action(initiator); if (action == NOISE_ACTION_WRITE_MESSAGE) { send = initiator; recv = responder; } else if (action == NOISE_ACTION_READ_MESSAGE) { send = responder; recv = initiator; } else { break; } /* Check that the objects have the right action for this step */ compare(noise_handshakestate_get_action(send), NOISE_ACTION_WRITE_MESSAGE); compare(noise_handshakestate_get_action(recv), NOISE_ACTION_READ_MESSAGE); /* Cannot perform the wrong operation on the sender or receiver */ noise_buffer_set_output(mbuf, message, sizeof(message)); noise_buffer_set_output(pbuf, payload, sizeof(payload)); compare(noise_handshakestate_read_message(send, &mbuf, &pbuf), NOISE_ERROR_INVALID_STATE); noise_buffer_set_output(mbuf, message, sizeof(message)); noise_buffer_set_input(pbuf, payload, sizeof(payload)); compare(noise_handshakestate_write_message(recv, &mbuf, &pbuf), NOISE_ERROR_INVALID_STATE); /* Parameter errors */ compare(noise_handshakestate_write_message(0, &mbuf, &pbuf), NOISE_ERROR_INVALID_PARAM); compare(noise_handshakestate_write_message(send, 0, &pbuf), NOISE_ERROR_INVALID_PARAM); mbuf.data = 0; compare(noise_handshakestate_write_message(send, &mbuf, &pbuf), NOISE_ERROR_INVALID_PARAM); noise_buffer_set_output(mbuf, message, sizeof(message)); pbuf.data = 0; compare(noise_handshakestate_write_message(send, &mbuf, &pbuf), NOISE_ERROR_INVALID_PARAM); noise_buffer_set_output(mbuf, message, sizeof(message)); noise_buffer_set_output(pbuf, payload, sizeof(payload)); compare(noise_handshakestate_read_message(0, &mbuf, &pbuf), NOISE_ERROR_INVALID_PARAM); compare(noise_handshakestate_read_message(recv, 0, &pbuf), NOISE_ERROR_INVALID_PARAM); mbuf.data = 0; compare(noise_handshakestate_read_message(recv, &mbuf, &pbuf), NOISE_ERROR_INVALID_PARAM); noise_buffer_set_output(mbuf, message, sizeof(message)); pbuf.data = 0; compare(noise_handshakestate_read_message(recv, &mbuf, &pbuf), NOISE_ERROR_INVALID_PARAM); /* Transfer the message to the other side properly */ noise_buffer_set_output(mbuf, message, sizeof(message)); noise_buffer_set_input(pbuf, payload, sizeof(payload)); compare(noise_handshakestate_write_message(send, &mbuf, &pbuf), NOISE_ERROR_NONE); noise_buffer_set_output(pbuf, payload, sizeof(payload)); compare(noise_handshakestate_read_message(recv, &mbuf, &pbuf), NOISE_ERROR_NONE); } /* Both handshakes should now have "split" */ compare(noise_handshakestate_get_action(initiator), NOISE_ACTION_SPLIT); compare(noise_handshakestate_get_action(responder), NOISE_ACTION_SPLIT); /* Check that the handshake hashes are identical */ compare(noise_handshakestate_get_handshake_hash(initiator, message, 64), NOISE_ERROR_NONE); compare(noise_handshakestate_get_handshake_hash(responder, message + 64, 64), NOISE_ERROR_NONE); verify(!memcmp(message, message + 64, 64)); /* Check handshake hash truncation */ memset(message, 0xAA, sizeof(message)); compare(noise_handshakestate_get_handshake_hash(initiator, message, 16), NOISE_ERROR_NONE); compare(noise_handshakestate_get_handshake_hash(responder, message + 64, 16), NOISE_ERROR_NONE); verify(!memcmp(message, message + 64, 16)); for (index = 16; index < 64; ++index) compare(message[index], 0xAA); /* Check for various error conditions */ compare(noise_handshakestate_get_protocol_id(0, &id2), NOISE_ERROR_INVALID_PARAM); compare(noise_handshakestate_get_protocol_id(initiator, 0), NOISE_ERROR_INVALID_PARAM); compare(noise_handshakestate_get_handshake_hash(0, message, 64), NOISE_ERROR_INVALID_PARAM); compare(noise_handshakestate_get_handshake_hash(initiator, 0, 64), NOISE_ERROR_INVALID_PARAM); /* Clean up */ compare(noise_handshakestate_free(initiator), NOISE_ERROR_NONE); compare(noise_handshakestate_free(responder), NOISE_ERROR_NONE); }