Example #1
0
static themis_status_t secure_session_proceed_client(secure_session_t *session_ctx, const void *data, size_t data_length, void *output, size_t *output_length)
{
	const soter_container_hdr_t *proto_message = data;
	const soter_container_hdr_t *peer_id;

	const soter_container_hdr_t *peer_ecdh_key;
	size_t peer_ecdh_key_length;

	const uint8_t *signature;
	size_t signature_length;

	themis_status_t res = THEMIS_SUCCESS;
	soter_status_t soter_status;

	uint8_t sign_key[1024]; /* Should be enough for RSA 8192 which is 512 bytes */
	size_t sign_key_length;

	uint8_t ecdh_key[1024];
	size_t ecdh_key_length = sizeof(ecdh_key);

	const soter_container_hdr_t *peer_sign_key;
	soter_kdf_context_buf_t sign_data[4];

	uint8_t *data_to_send = output;
	size_t length_to_send;

	soter_container_hdr_t *container;
	uint8_t *mac;

	if (data_length < sizeof(soter_container_hdr_t))
	{
		return THEMIS_INVALID_PARAMETER;
	}

	if (memcmp(proto_message->tag, THEMIS_SESSION_PROTO_TAG, SOTER_CONTAINER_TAG_LENGTH))
	{
		return THEMIS_INVALID_PARAMETER;
	}

	if (data_length < (soter_container_data_size(proto_message) + sizeof(soter_container_hdr_t)))
	{
		return THEMIS_INVALID_PARAMETER;
	}

	if (THEMIS_SUCCESS != soter_verify_container_checksum(proto_message))
	{
		return THEMIS_INVALID_PARAMETER;
	}

	peer_id = (const soter_container_hdr_t *)soter_container_const_data(proto_message);

	if (memcmp(peer_id->tag, THEMIS_SESSION_ID_TAG, SOTER_CONTAINER_TAG_LENGTH))
	{
		return THEMIS_INVALID_PARAMETER;
	}

	if (THEMIS_SUCCESS != soter_verify_container_checksum(peer_id))
	{
		return THEMIS_INVALID_PARAMETER;
	}

	peer_ecdh_key = (const soter_container_hdr_t *)(soter_container_const_data(peer_id) + soter_container_data_size(peer_id));

	if (memcmp(peer_ecdh_key->tag, EC_PUB_KEY_PREF, strlen(EC_PUB_KEY_PREF)))
	{
		return THEMIS_INVALID_PARAMETER;
	}

	peer_ecdh_key_length = ntohl(peer_ecdh_key->size);

	signature = (const uint8_t *)peer_ecdh_key + peer_ecdh_key_length;
	signature_length = (const uint8_t *)data + soter_container_data_size(proto_message) + sizeof(soter_container_hdr_t) - signature;
	if (session_ctx->user_callbacks->get_public_key_for_id(soter_container_const_data(peer_id), soter_container_data_size(peer_id), sign_key, sizeof(sign_key), session_ctx->user_callbacks->user_data))
	{
		return THEMIS_SSESSION_GET_PUB_FOR_ID_CALLBACK_ERROR;
	}

	peer_sign_key = (const soter_container_hdr_t *)sign_key;

	if (memcmp(peer_sign_key->tag, EC_PUB_KEY_PREF, strlen(EC_PUB_KEY_PREF)))
	{
		return THEMIS_INVALID_PARAMETER;
	}

	sign_key_length = ntohl(peer_sign_key->size);

	if (sizeof(soter_container_hdr_t) >= sign_key_length)
	{
		return THEMIS_INVALID_PARAMETER;
	}

	soter_status = soter_asym_ka_export_key(&(session_ctx->ecdh_ctx), ecdh_key, &ecdh_key_length, false);
	if (THEMIS_SUCCESS != soter_status)
	{
		return soter_status;
	}

	sign_data[0].data = (const uint8_t *)peer_ecdh_key;
	sign_data[0].length = peer_ecdh_key_length;

	sign_data[1].data = ecdh_key;
	sign_data[1].length = ecdh_key_length;

	sign_data[2].data = soter_container_const_data(peer_id);
	sign_data[2].length = soter_container_data_size(peer_id);

	sign_data[3].data = session_ctx->we.id;
	sign_data[3].length = session_ctx->we.id_length;

	res = verify_signature(peer_sign_key, sign_key_length, sign_data, 4, signature, signature_length);
	if (THEMIS_SUCCESS != res)
	{
		return res;
	}

	res = secure_session_peer_init(&(session_ctx->peer), soter_container_const_data(peer_id), soter_container_data_size(peer_id), peer_ecdh_key, peer_ecdh_key_length, peer_sign_key, sign_key_length);
	if (THEMIS_SUCCESS != res)
	{
		goto err;
	}

	sign_data[0].data = ecdh_key;
	sign_data[0].length = ecdh_key_length;

	sign_data[1].data = (const uint8_t *)peer_ecdh_key;
	sign_data[1].length = peer_ecdh_key_length;

	sign_data[2].data = session_ctx->we.id;
	sign_data[2].length = session_ctx->we.id_length;

	sign_data[3].data = soter_container_const_data(peer_id);
	sign_data[3].length = soter_container_data_size(peer_id);

	res = soter_kdf(NULL, 0, SESSION_ID_GENERATION_LABEL, sign_data, 4, &(session_ctx->session_id), sizeof(session_ctx->session_id));
	if (THEMIS_SUCCESS != res)
	{
		goto err;
	}

	/* we will reuse sign_key buffer for shared secret computation */
	sign_key_length = sizeof(sign_key);
	res = soter_asym_ka_derive(&(session_ctx->ecdh_ctx), peer_ecdh_key, peer_ecdh_key_length, sign_key, &sign_key_length);
	if (THEMIS_SUCCESS != res)
	{
		goto err;
	}

	sign_data[0].data = (const uint8_t *)(&(session_ctx->session_id));
	sign_data[0].length = sizeof(session_ctx->session_id);

	res = soter_kdf(sign_key, sign_key_length, SESSION_MASTER_KEY_GENERATION_LABEL, sign_data, 1, session_ctx->session_master_key, sizeof(session_ctx->session_master_key));
	if (THEMIS_SUCCESS != res)
	{
		goto err;
	}

	/* restore sign data for signature computation */
	sign_data[0].data = ecdh_key;
	sign_data[0].length = ecdh_key_length;

	res = compute_signature(session_ctx->we.sign_key, session_ctx->we.sign_key_length, NULL, 0, NULL, &signature_length);
	if (THEMIS_BUFFER_TOO_SMALL != res)
	{
		goto err;
	}

	/* we will reuse sign_key_length for mac length retrieval */
	res = compute_mac(session_ctx->session_master_key, sizeof(session_ctx->session_master_key), NULL, 0, NULL, &sign_key_length);
	if (THEMIS_BUFFER_TOO_SMALL != res)
	{
		goto err;
	}

	length_to_send = sizeof(soter_container_hdr_t) + signature_length + sign_key_length;
	if ((NULL == output) || (*output_length < length_to_send))
	{
		*output_length = length_to_send;
		res = THEMIS_BUFFER_TOO_SMALL;
		goto err;
	}

	container = (soter_container_hdr_t *)data_to_send;

	/* Actual signature may be 1 or 2 bytes less than reported above because leading zeroes are stripped */
	length_to_send -= signature_length;

	res = compute_signature(session_ctx->we.sign_key, session_ctx->we.sign_key_length, sign_data, 4, soter_container_data(container), &signature_length);
	if (THEMIS_SUCCESS != res)
	{
		goto err;
	}

	length_to_send += signature_length;
	mac = soter_container_data(container) + signature_length;

	sign_data[0].data = (const uint8_t *)(session_ctx->peer.ecdh_key);
	sign_data[0].length = session_ctx->peer.ecdh_key_length;

	sign_data[1].data = (const uint8_t *)(&(session_ctx->session_id));
	sign_data[1].length = sizeof(session_ctx->session_id);

	res = compute_mac(session_ctx->session_master_key, sizeof(session_ctx->session_master_key), sign_data, 2, mac, &sign_key_length);
	if (THEMIS_SUCCESS != res)
	{
		goto err;
	}

	*output_length = length_to_send;

	memcpy(container->tag, THEMIS_SESSION_PROTO_TAG, SOTER_CONTAINER_TAG_LENGTH);
	soter_container_set_data_size(container, length_to_send - sizeof(soter_container_hdr_t));
	soter_update_container_checksum(container);

	/* "Client mode": waiting final confirmation from server */
	session_ctx->state_handler = secure_session_finish_client;

err:

	if (THEMIS_SUCCESS != res)
	{
		secure_session_peer_cleanup(&(session_ctx->peer));
	}

	return res;
}
Example #2
0
themis_status_t secure_session_generate_connect_request(secure_session_t *session_ctx, void *output, size_t *output_length)
{
	uint8_t *data_to_send = output;
	size_t length_to_send;

	soter_container_hdr_t *container;

	size_t ecdh_key_length = 0;
	size_t signature_length = 0;

	soter_status_t soter_status;
	themis_status_t res = THEMIS_SUCCESS;

	soter_kdf_context_buf_t sign_data;

	soter_status = soter_asym_ka_export_key(&(session_ctx->ecdh_ctx), NULL, &ecdh_key_length, false);
	if (THEMIS_BUFFER_TOO_SMALL != soter_status)
	{
	    return soter_status;
	}
	res = compute_signature(session_ctx->we.sign_key, session_ctx->we.sign_key_length, NULL, 0, NULL, &signature_length);
	if (THEMIS_BUFFER_TOO_SMALL != res)
	{
		return res;
	}
	length_to_send = 2 * sizeof(soter_container_hdr_t) + session_ctx->we.id_length + ecdh_key_length + signature_length;
	if ((NULL == output) || (*output_length < length_to_send))
	{
		*output_length = length_to_send;
		return THEMIS_BUFFER_TOO_SMALL;
	}

	/* Storing ID in a container */
	container = ((soter_container_hdr_t *)data_to_send) + 1;

	memcpy(container->tag, THEMIS_SESSION_ID_TAG, SOTER_CONTAINER_TAG_LENGTH);
	soter_container_set_data_size(container, session_ctx->we.id_length);
	memcpy(soter_container_data(container), session_ctx->we.id, session_ctx->we.id_length);
	soter_update_container_checksum(container);

	/* Moving back to beginning of allocated buffer */
	container = (soter_container_hdr_t *)data_to_send;

	soter_status = soter_asym_ka_export_key(&(session_ctx->ecdh_ctx), data_to_send + (2 * sizeof(soter_container_hdr_t)) + session_ctx->we.id_length, &ecdh_key_length, false);
	if (THEMIS_SUCCESS != soter_status)
	{
		return soter_status;
	}
	sign_data.data = data_to_send + (2 * sizeof(soter_container_hdr_t)) + session_ctx->we.id_length;
	sign_data.length = ecdh_key_length;

	/* Actual signature may be 1 or 2 bytes less than reported above because leading zeroes are stripped */
	length_to_send -= signature_length;

	res = compute_signature(session_ctx->we.sign_key, session_ctx->we.sign_key_length, &sign_data, 1, data_to_send + (2 * sizeof(soter_container_hdr_t)) + session_ctx->we.id_length + ecdh_key_length, &signature_length);
	if (THEMIS_SUCCESS != res)
	{
		return res;
	}

	length_to_send += signature_length;
	*output_length = length_to_send;

	memcpy(container->tag, THEMIS_SESSION_PROTO_TAG, SOTER_CONTAINER_TAG_LENGTH);
	soter_container_set_data_size(container, length_to_send - sizeof(soter_container_hdr_t));
	soter_update_container_checksum(container);

	/* In "client mode" awaiting initial response from the server */
	session_ctx->state_handler = secure_session_proceed_client;
	session_ctx->is_client = true;

	if (session_ctx->user_callbacks->state_changed)
	{
		session_ctx->user_callbacks->state_changed(STATE_NEGOTIATING, session_ctx->user_callbacks->user_data);
	}

	return THEMIS_SUCCESS;
}
Example #3
0
static themis_status_t secure_session_accept(secure_session_t *session_ctx, const void *data, size_t data_length, void *output, size_t *output_length)
{
	const soter_container_hdr_t *proto_message = data;
	const soter_container_hdr_t *peer_id;

	const soter_container_hdr_t *peer_ecdh_key;
	size_t peer_ecdh_key_length;

	const uint8_t *signature;
	size_t signature_length;

	themis_status_t res = THEMIS_SUCCESS;
	soter_status_t soter_status;

	uint8_t sign_key[1024]; /* Should be enough for RSA 8192 which is 512 bytes */
	size_t sign_key_length;

	const soter_container_hdr_t *peer_sign_key;
	soter_kdf_context_buf_t sign_data[4];

	uint8_t *data_to_send = output;
	size_t length_to_send;

	size_t ecdh_key_length = 0;
	soter_container_hdr_t *container;

	if (data_length < sizeof(soter_container_hdr_t))
	{
		return THEMIS_INVALID_PARAMETER;
	}

	if (memcmp(proto_message->tag, THEMIS_SESSION_PROTO_TAG, SOTER_CONTAINER_TAG_LENGTH))
	{
		return THEMIS_INVALID_PARAMETER;
	}

	if (data_length < (soter_container_data_size(proto_message) + sizeof(soter_container_hdr_t)))
	{
		return THEMIS_INVALID_PARAMETER;
	}

	if (THEMIS_SUCCESS != soter_verify_container_checksum(proto_message))
	{

		return THEMIS_INVALID_PARAMETER;
	}

	peer_id = (const soter_container_hdr_t *)soter_container_const_data(proto_message);

	if (memcmp(peer_id->tag, THEMIS_SESSION_ID_TAG, SOTER_CONTAINER_TAG_LENGTH))
	{
		return THEMIS_INVALID_PARAMETER;
	}

	if (THEMIS_SUCCESS != soter_verify_container_checksum(peer_id))
	{
		return THEMIS_INVALID_PARAMETER;
	}

	peer_ecdh_key = (const soter_container_hdr_t *)(soter_container_const_data(peer_id) + soter_container_data_size(peer_id));

	if (memcmp(peer_ecdh_key->tag, EC_PUB_KEY_PREF, strlen(EC_PUB_KEY_PREF)))
	{
		return THEMIS_INVALID_PARAMETER;
	}

	peer_ecdh_key_length = soter_container_data_size(peer_ecdh_key) + sizeof(soter_container_hdr_t);

	signature = (const uint8_t *)peer_ecdh_key + peer_ecdh_key_length;
	signature_length = (const uint8_t *)data + soter_container_data_size(proto_message) + sizeof(soter_container_hdr_t) - signature;
	if (session_ctx->user_callbacks->get_public_key_for_id(soter_container_const_data(peer_id), soter_container_data_size(peer_id), sign_key, sizeof(sign_key), session_ctx->user_callbacks->user_data))
	{
		return THEMIS_SSESSION_GET_PUB_FOR_ID_CALLBACK_ERROR;
	}

	peer_sign_key = (const soter_container_hdr_t *)sign_key;

	if (memcmp(peer_sign_key->tag, EC_PUB_KEY_PREF, strlen(EC_PUB_KEY_PREF)))
	{
		return THEMIS_INVALID_PARAMETER;
	}

	sign_key_length = ntohl(peer_sign_key->size);

	if (sizeof(soter_container_hdr_t) >= sign_key_length)
	{
		return THEMIS_INVALID_PARAMETER;
	}

	sign_data[0].data = (const uint8_t *)peer_ecdh_key;
	sign_data[0].length = peer_ecdh_key_length;

	res = verify_signature(peer_sign_key, sign_key_length, sign_data, 1, signature, signature_length);
	if (THEMIS_SUCCESS != res)
	{
		return res;
	}

	/* Preparing to send response */
	res = compute_signature(session_ctx->we.sign_key, session_ctx->we.sign_key_length, NULL, 0, NULL, &signature_length);
	if (THEMIS_BUFFER_TOO_SMALL != res)
	{
		return res;
	}

	soter_status = soter_asym_ka_export_key(&(session_ctx->ecdh_ctx), NULL, &ecdh_key_length, false);
	if (THEMIS_BUFFER_TOO_SMALL != soter_status)
	{
		return soter_status;
	}

	length_to_send = 2 * sizeof(soter_container_hdr_t) + session_ctx->we.id_length + ecdh_key_length + signature_length;
	if ((NULL == output) || (*output_length < length_to_send))
	{
		*output_length = length_to_send;
		return THEMIS_BUFFER_TOO_SMALL;
	}

	res = secure_session_peer_init(&(session_ctx->peer), soter_container_const_data(peer_id), soter_container_data_size(peer_id), peer_ecdh_key, peer_ecdh_key_length, peer_sign_key, sign_key_length);
	if (THEMIS_SUCCESS != res)
	{
		goto err;
	}

	/* Storing ID in a container */
	container = (soter_container_hdr_t *)data_to_send + 1;

	memcpy(container->tag, THEMIS_SESSION_ID_TAG, SOTER_CONTAINER_TAG_LENGTH);
	soter_container_set_data_size(container, session_ctx->we.id_length);
	memcpy(soter_container_data(container), session_ctx->we.id, session_ctx->we.id_length);
	soter_update_container_checksum(container);

	/* Moving back to beginning of allocated buffer */
	container = (soter_container_hdr_t *)data_to_send;

	soter_status = soter_asym_ka_export_key(&(session_ctx->ecdh_ctx), data_to_send + (2 * sizeof(soter_container_hdr_t)) + session_ctx->we.id_length, &ecdh_key_length, false);
	if (THEMIS_SUCCESS != soter_status)
	{
		res = soter_status;
		goto err;
	}

	sign_data[0].data = data_to_send + (2 * sizeof(soter_container_hdr_t)) + session_ctx->we.id_length;
	sign_data[0].length = ecdh_key_length;

	sign_data[1].data = session_ctx->peer.ecdh_key;
	sign_data[1].length = session_ctx->peer.ecdh_key_length;

	sign_data[2].data = session_ctx->we.id;
	sign_data[2].length = session_ctx->we.id_length;

	sign_data[3].data = session_ctx->peer.id;
	sign_data[3].length = session_ctx->peer.id_length;

	/* Actual signature may be 1 or 2 bytes less than reported above because leading zeroes are stripped */
	length_to_send -= signature_length;

	res = compute_signature(session_ctx->we.sign_key, session_ctx->we.sign_key_length, sign_data, 4, data_to_send + (2 * sizeof(soter_container_hdr_t)) + session_ctx->we.id_length + ecdh_key_length, &signature_length);
	if (THEMIS_SUCCESS != res)
	{
		goto err;
	}

	length_to_send += signature_length;
	*output_length = length_to_send;

	memcpy(container->tag, THEMIS_SESSION_PROTO_TAG, SOTER_CONTAINER_TAG_LENGTH);
	soter_container_set_data_size(container, length_to_send - sizeof(soter_container_hdr_t));
	soter_update_container_checksum(container);

	/* "Server mode": waiting response from the client */
	session_ctx->state_handler = secure_session_finish_server;

	if (session_ctx->user_callbacks->state_changed)
	{
		session_ctx->user_callbacks->state_changed(STATE_NEGOTIATING, session_ctx->user_callbacks->user_data);
	}

err:

	if (THEMIS_SUCCESS != res)
	{
		secure_session_peer_cleanup(&(session_ctx->peer));
	}

	return res;
}
Example #4
0
static STSStatus compose_post_data(char* buffer, uint32_t bufferSize,
                            CommonRequestContext* commonContext,
                            AssumeRoleRequestContext* assumeRoleContext)
{
    string_buffer(queryParams, 2048*3);
    string_buffer_initialize(queryParams);
    char* queryParamsArray[32];
    int paramsCount = 0;
    int len = 0;
    int start = 0;
    int amp = 0;

#define safe_append(isNewParam, name, value)                            \
    do {                                                                \
        int fit;                                                        \
        start = len;                                                    \
        if (amp) { start++; }                                           \
        if (isNewParam) {                                               \
            queryParamsArray[paramsCount++] = &(queryParams[start]);    \
        }                                                               \
        if (amp) {                                                      \
            string_buffer_append(queryParams, "&", 1, fit);             \
            if (!fit) {                                                 \
                return STSStatusUriTooLong;                             \
            }                                                           \
            len++;                                                      \
        }                                                               \
        string_buffer_append(queryParams, name "=",                     \
                            sizeof(name "=") - 1, fit);                 \
        if (!fit) {                                                     \
            return STSStatusUriTooLong;                                 \
        }                                                               \
        len += strlen(name) + 1;                                        \
        amp = 1;                                                        \
        string_buffer_append(queryParams, value, strlen(value), fit);   \
        len += strlen(value);                                           \
    } while (0)

    time_t now = time(NULL);
    char timebuf[256];
    strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
    
    STSUUID uuid;
    char* uuidString;
    uuid_create(&uuid);
    uuid_to_string(&uuid, &uuidString);
    
    char durationSeconds[10];
    snprintf(durationSeconds, 10, "%d", assumeRoleContext->durationSeconds);

    safe_append(1, "Format", "JSON");
    safe_append(1, "Version", "2015-04-01");
    safe_append(1, "SignatureVersion", "1.0");
    safe_append(1, "SignatureMethod", "HMAC-SHA1");
    safe_append(1, "SignatureNonce", uuidString);
    safe_append(1, "Timestamp", timebuf);
    safe_append(1, "Action", commonContext->action);
    safe_append(1, "AccessKeyId", commonContext->accessKeyId);
    safe_append(1, "RoleArn", assumeRoleContext->RoleArn);
    safe_append(1, "RoleSessionName", assumeRoleContext->RoleSessionName);
    safe_append(1, "Policy", assumeRoleContext->policy);
    safe_append(1, "DurationSeconds", durationSeconds);
    
    params_array_sort(queryParamsArray, paramsCount);
    
    string_buffer(signature, 256);
    string_buffer_initialize(signature);
    compute_signature(signature, 256, queryParamsArray, paramsCount, commonContext->accessKeySecret);
    
    compose_url_encoded_post_data(buffer, bufferSize, queryParams, strlen(queryParams), signature);
    
    free(uuidString);
    return STSStatusOK;
}