Example #1
0
/* Check that "IK" correctly falls back to "XXfallback" */
static void check_fallback_protocol
    (const char *name, int fallback_anyway, int trial_initiator_decrypt)
{
    NoiseHandshakeState *initiator;
    NoiseHandshakeState *responder;
    NoiseDHState *dh;
    uint8_t message[4096];
    uint8_t message2[4096];
    uint8_t payload[23];
    NoiseBuffer mbuf;
    NoiseBuffer pbuf;

    /* Set the name of this test for error reporting */
    data_name = name;

    /* Create the two objects for an initial "IK" handshake */
    compare(noise_handshakestate_new_by_name
                (&initiator, name, NOISE_ROLE_INITIATOR),
            NOISE_ERROR_NONE);
    compare(noise_handshakestate_new_by_name
                (&responder, name, NOISE_ROLE_RESPONDER),
            NOISE_ERROR_NONE);

    /* Set up the keys.  The responder uses an alternate key that is
       different from the one expected by the initiator */
    compare(noise_handshakestate_set_prologue(initiator, "Hello", 5),
            NOISE_ERROR_NONE);
    compare(noise_handshakestate_set_prologue(responder, "Hello", 5),
            NOISE_ERROR_NONE);
    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);
    }
    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);
    }
    dh = noise_handshakestate_get_local_keypair_dh(responder);
    if (!fallback_anyway) {
        if (noise_dhstate_get_dh_id(dh) == NOISE_DH_CURVE25519) {
            compare(noise_dhstate_set_keypair_private
                        (dh, resp_private_25519_alt, sizeof(resp_private_25519_alt)),
                    NOISE_ERROR_NONE);
        } else {
            compare(noise_dhstate_set_keypair_private
                        (dh, resp_private_448_alt, sizeof(resp_private_448_alt)),
                    NOISE_ERROR_NONE);
        }
    } else {
        /* Matching keys, but the responder will fallback anyway */
        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);
        }
    }
    if (noise_handshakestate_needs_pre_shared_key(initiator)) {
        compare(noise_handshakestate_set_pre_shared_key
                    (initiator, psk, sizeof(psk)),
                NOISE_ERROR_NONE);
        compare(noise_handshakestate_set_pre_shared_key
                    (responder, psk, sizeof(psk)),
                NOISE_ERROR_NONE);
    }

    /* Start the handshakes running */
    compare(noise_handshakestate_start(initiator), NOISE_ERROR_NONE);
    compare(noise_handshakestate_start(responder), NOISE_ERROR_NONE);

    /* Create the first outgoing "IK" packet from the initiator */
    memset(message, 0, sizeof(message));
    memset(payload, 0x66, sizeof(payload));
    noise_buffer_set_output(mbuf, message, sizeof(message));
    noise_buffer_set_input(pbuf, payload, sizeof(payload));
    compare(noise_handshakestate_write_message(initiator, &mbuf, &pbuf),
            NOISE_ERROR_NONE);

    /* Read the message on the responder side */
    if (!fallback_anyway) {
        noise_buffer_set_output(pbuf, payload, sizeof(payload));
        compare(noise_handshakestate_read_message(responder, &mbuf, &pbuf),
                NOISE_ERROR_MAC_FAILURE);
    } else {
        /* The "IK" handshake was successful, but we decide to ignore that
           and change to "XXfallback" anyway */
        noise_buffer_set_output(pbuf, payload, sizeof(payload));
        compare(noise_handshakestate_read_message(responder, &mbuf, &pbuf),
                NOISE_ERROR_NONE);
    }

    /* Fallback on the responder side */
    compare(noise_handshakestate_fallback(responder), NOISE_ERROR_NONE);
    compare(noise_handshakestate_get_role(initiator), NOISE_ROLE_INITIATOR);
    compare(noise_handshakestate_get_role(responder), NOISE_ROLE_INITIATOR);

    /* Supply the prologue and the PSK again to the responder */
    compare(noise_handshakestate_set_prologue(responder, "Hello", 5),
            NOISE_ERROR_NONE);
    if (noise_handshakestate_needs_pre_shared_key(responder)) {
        compare(noise_handshakestate_set_pre_shared_key
                    (responder, psk, sizeof(psk)),
                NOISE_ERROR_NONE);
    }
    compare(noise_handshakestate_start(responder), NOISE_ERROR_NONE);

    /* Write a new message back to the initiator */
    memset(payload, 0xAA, sizeof(payload));
    noise_buffer_set_output(mbuf, message, sizeof(message));
    noise_buffer_set_input(pbuf, payload, sizeof(payload));
    compare(noise_handshakestate_write_message(responder, &mbuf, &pbuf),
            NOISE_ERROR_NONE);

    /* Optionally perform a trial decryption first, which will fail */
    if (trial_initiator_decrypt) {
        memcpy(message2, message, sizeof(message));
        noise_buffer_set_output(pbuf, payload, sizeof(payload));
        compare(noise_handshakestate_read_message(initiator, &mbuf, &pbuf),
                NOISE_ERROR_MAC_FAILURE);
        memcpy(message, message2, sizeof(message));
    }

    /* Fallback on the initiator side */
    compare(noise_handshakestate_fallback(initiator), NOISE_ERROR_NONE);
    compare(noise_handshakestate_get_role(initiator), NOISE_ROLE_RESPONDER);
    compare(noise_handshakestate_get_role(responder), NOISE_ROLE_INITIATOR);

    /* Supply the prologue and the PSK again to the initiator */
    compare(noise_handshakestate_set_prologue(initiator, "Hello", 5),
            NOISE_ERROR_NONE);
    if (noise_handshakestate_needs_pre_shared_key(initiator)) {
        compare(noise_handshakestate_set_pre_shared_key
                    (initiator, psk, sizeof(psk)),
                NOISE_ERROR_NONE);
    }
    compare(noise_handshakestate_start(initiator), NOISE_ERROR_NONE);

    /* Read the message on the initiator side */
    noise_buffer_set_output(pbuf, payload, sizeof(payload));
    compare(noise_handshakestate_read_message(initiator, &mbuf, &pbuf),
            NOISE_ERROR_NONE);

    /* Send the next "XXfallback" message from the initiator side */
    memset(payload, 0x66, sizeof(payload));
    noise_buffer_set_output(mbuf, message, sizeof(message));
    noise_buffer_set_input(pbuf, payload, sizeof(payload));
    compare(noise_handshakestate_write_message(initiator, &mbuf, &pbuf),
            NOISE_ERROR_NONE);

    /* Receive the message on the responder side */
    noise_buffer_set_output(pbuf, payload, sizeof(payload));
    compare(noise_handshakestate_read_message(responder, &mbuf, &pbuf),
            NOISE_ERROR_NONE);

    /* Both sides should now be in the "split" condition */
    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));

    /* Clean up */
    compare(noise_handshakestate_free(initiator), NOISE_ERROR_NONE);
    compare(noise_handshakestate_free(responder), NOISE_ERROR_NONE);
}
Example #2
0
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) {
Example #3
0
/* 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);
}