Example #1
0
/**
 * \brief Creates a new SymmetricState object from a protocol name.
 *
 * \param state Points to the variable where to store the pointer to
 * the new SymmetricState object.
 * \param name The name of the Noise protocol to use.  This string
 * must be NUL-terminated.
 *
 * \return NOISE_ERROR_NONE on success.
 * \return NOISE_ERROR_INVALID_PARAM if \a state or \a name is NULL.
 * \return NOISE_ERROR_UNKNOWN_NAME if the protocol \a name is unknown.
 * \return NOISE_ERROR_INVALID_LENGTH if the lengths of the hash output
 * or the cipher key are incompatible.
 * \return NOISE_ERROR_NO_MEMORY if there is insufficient memory to
 * allocate the new SymmetricState object.
 *
 * \sa noise_symmetricstate_free(), noise_symmetricstate_new_by_id()
 */
int noise_symmetricstate_new_by_name
    (NoiseSymmetricState **state, const char *name)
{
    NoiseProtocolId id;
    size_t name_len;
    int err;

    /* Validate the parameters */
    if (!state)
        return NOISE_ERROR_INVALID_PARAM;
    *state = 0;
    if (!name)
        return NOISE_ERROR_INVALID_PARAM;

    /* Parse the protocol identifier and validate the names */
    name_len = strlen(name);
    err = noise_protocol_name_to_id(&id, name, name_len);
    if (err != NOISE_ERROR_NONE)
        return err;

    /* Create the SymmetricState object */
    return noise_symmetricstate_new(state, name, &id);
}
Example #2
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);
}