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);
}
Exemple #2
0
/* Initialize's the handshake with all necessary keys */
static int initialize_handshake
    (NoiseHandshakeState *handshake, const NoiseProtocolId *nid,
     const void *prologue, size_t prologue_len)
{
    NoiseDHState *dh;
    int dh_id;
    int err;

    /* Set the prologue first */
    err = noise_handshakestate_set_prologue(handshake, prologue, prologue_len);
    if (err != NOISE_ERROR_NONE) {
        noise_perror("prologue", err);
        return 0;
    }

    /* Set the PSK if one is needed */
    if (nid->prefix_id == NOISE_PREFIX_PSK) {
        err = noise_handshakestate_set_pre_shared_key
            (handshake, psk, sizeof(psk));
        if (err != NOISE_ERROR_NONE) {
            noise_perror("psk", err);
            return 0;
        }
    }

    /* Set the local keypair for the server based on the DH algorithm */
    if (noise_handshakestate_needs_local_keypair(handshake)) {
        dh = noise_handshakestate_get_local_keypair_dh(handshake);
        dh_id = noise_dhstate_get_dh_id(dh);
        if (dh_id == NOISE_DH_CURVE25519) {
            err = noise_dhstate_set_keypair_private
                (dh, server_key_25519, sizeof(server_key_25519));
        } else if (dh_id == NOISE_DH_CURVE448) {
            err = noise_dhstate_set_keypair_private
                (dh, server_key_448, sizeof(server_key_448));
        } else {
            err = NOISE_ERROR_UNKNOWN_ID;
        }
        if (err != NOISE_ERROR_NONE) {
            noise_perror("set server private key", err);
            return 0;
        }
    }

    /* Set the remote public key for the client */
    if (noise_handshakestate_needs_remote_public_key(handshake)) {
        dh = noise_handshakestate_get_remote_public_key_dh(handshake);
        dh_id = noise_dhstate_get_dh_id(dh);
        if (dh_id == NOISE_DH_CURVE25519) {
            err = noise_dhstate_set_public_key
                (dh, client_key_25519, sizeof(client_key_25519));
        } else if (dh_id == NOISE_DH_CURVE25519) {
            err = noise_dhstate_set_public_key
                (dh, client_key_448, sizeof(client_key_448));
        } else {
            err = NOISE_ERROR_UNKNOWN_ID;
        }
        if (err != NOISE_ERROR_NONE) {
            noise_perror("set client public key", err);
            return 0;
        }
    }

    /* Set the fixed local ephemeral value if necessary */
    if (fixed_ephemeral) {
        dh = noise_handshakestate_get_fixed_ephemeral_dh(handshake);
        if (noise_dhstate_get_dh_id(dh) == NOISE_DH_CURVE25519) {
            err = noise_dhstate_set_keypair_private
                (dh, fixed_ephemeral_25519, sizeof(fixed_ephemeral_25519));
        } else {
            err = noise_dhstate_set_keypair_private
                (dh, fixed_ephemeral_448, sizeof(fixed_ephemeral_448));
        }
        if (err != NOISE_ERROR_NONE) {
            noise_perror("fixed ephemeral value", err);
            return 0;
        }
    }

    /* Ready to go */
    return 1;
}
/* 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);
}