1、客户端选择认证方法
Client authentication method selection
抓包分析
{
Authentication selected by client: Spice (1)
}
代码分析
spice_channel_send_link(channel);
if (!spice_channel_recv_link_hdr(channel) ||
!spice_channel_recv_link_msg(channel) ||
!spice_channel_recv_auth(channel))
goto cleanup;
while (spice_channel_iterate(channel));
if (!spice_channel_test_common_capability(channel, SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION)) {
CHANNEL_DEBUG(channel, "Server supports spice ticket auth only");
if ((event = spice_channel_send_spice_ticket(channel)) != SPICE_CHANNEL_NONE)
goto error;
} else {
SpiceLinkAuthMechanism auth = { 0, };
if (spice_channel_test_common_capability(channel, SPICE_COMMON_CAP_AUTH_SPICE)) {
auth.auth_mechanism = GUINT32_TO_LE(SPICE_COMMON_CAP_AUTH_SPICE); //发送spice认证方式
spice_channel_write(channel, &auth, sizeof(auth));
if ((event = spice_channel_send_spice_ticket(channel)) != SPICE_CHANNEL_NONE) //发送client ticket
goto error;
} else {
g_warning("No compatible AUTH mechanism");
goto error;
}
}
2、Client ticket
抓包分析
{
Ticket - client: 542...
}
代码分析
if (!spice_channel_test_common_capability(channel, SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION)) {
CHANNEL_DEBUG(channel, "Server supports spice ticket auth only");
if ((event = spice_channel_send_spice_ticket(channel)) != SPICE_CHANNEL_NONE)
goto error;
} else {
SpiceLinkAuthMechanism auth = { 0, };
if (spice_channel_test_common_capability(channel, SPICE_COMMON_CAP_AUTH_SPICE)) {
auth.auth_mechanism = GUINT32_TO_LE(SPICE_COMMON_CAP_AUTH_SPICE); //发送spice认证方式
spice_channel_write(channel, &auth, sizeof(auth));
if ((event = spice_channel_send_spice_ticket(channel)) != SPICE_CHANNEL_NONE) //发送client ticket
goto error;
} else {
g_warning("No compatible AUTH mechanism");
goto error;
}
}
3、Server ticket
抓包分析
{
Link result: OK (0)
}
代码分析
static void reds_handle_read_link_done(void *opaque)
{
auto link = static_cast<RedLinkInfo *>(opaque);
RedsState *reds = link->reds;
SpiceLinkMess *link_mess = link->link_mess;
uint32_t num_caps;
uint32_t *caps;
int auth_selection;
unsigned int i;
link_mess->caps_offset = GUINT32_FROM_LE(link_mess->caps_offset);
link_mess->connection_id = GUINT32_FROM_LE(link_mess->connection_id);
link_mess->num_channel_caps = GUINT32_FROM_LE(link_mess->num_channel_caps);
link_mess->num_common_caps = GUINT32_FROM_LE(link_mess->num_common_caps);
/* Prevent DoS. Currently we defined only 13 capabilities,
* I expect 1024 to be valid for quite a lot time */
if (link_mess->num_channel_caps > 1024 || link_mess->num_common_caps > 1024) {
reds_send_link_error(link, SPICE_LINK_ERR_INVALID_DATA);
reds_link_free(link);
return;
}
num_caps = link_mess->num_common_caps + link_mess->num_channel_caps;
caps = reinterpret_cast<uint32_t *>(reinterpret_cast<uint8_t *>(link_mess) +link_mess->caps_offset);
if (num_caps && (num_caps * sizeof(uint32_t) + link_mess->caps_offset > link->link_header.size || link_mess->caps_offset < sizeof(*link_mess))) {
reds_send_link_error(link, SPICE_LINK_ERR_INVALID_DATA);
reds_link_free(link);
return;
}
for(i = 0; i < num_caps;i++)
caps[i] = GUINT32_FROM_LE(caps[i]);
auth_selection = red_link_info_test_capability(link,SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION);
if (!reds_security_check(link)) {
if (red_stream_is_ssl(link->stream)) {
spice_warning("spice channels %d should not be encrypted", link_mess->channel_type);
reds_send_link_error(link, SPICE_LINK_ERR_NEED_UNSECURED);
} else {
spice_warning("spice channels %d should be encrypted", link_mess->channel_type);
reds_send_link_error(link, SPICE_LINK_ERR_NEED_SECURED);
}
reds_link_free(link);
return;
}
if (!reds_send_link_ack(reds, link)) {
reds_link_free(link);
return;
}
if (!auth_selection) {
if (reds->config->sasl_enabled && !link->skip_auth) {
spice_warning("SASL enabled, but peer supports only spice authentication");
reds_send_link_error(link, SPICE_LINK_ERR_VERSION_MISMATCH);
return;
}
spice_warning("Peer doesn't support AUTH selection");
reds_get_spice_ticket(link);
} else {
red_stream_async_read(link->stream, reinterpret_cast<uint8_t *>(&link->auth_mechanism),
sizeof(SpiceLinkAuthMechanism), reds_handle_auth_mechanism, link);
}
}
发送ticket数据包
static void reds_handle_auth_mechanism(void *opaque)
{
auto link = static_cast<RedLinkInfo *>(opaque);
RedsState *reds = link->reds;
spice_debug("Auth method: %d", link->auth_mechanism.auth_mechanism);
link->auth_mechanism.auth_mechanism = GUINT32_FROM_LE(link->auth_mechanism.auth_mechanism);
if (link->auth_mechanism.auth_mechanism == SPICE_COMMON_CAP_AUTH_SPICE&& !reds->config->sasl_enabled) {
reds_get_spice_ticket(link);
#if HAVE_SASL
} else if (link->auth_mechanism.auth_mechanism == SPICE_COMMON_CAP_AUTH_SASL) {
spice_debug("Starting SASL");
reds_start_auth_sasl(link);
#endif
} else {
spice_warning("Unknown auth method, disconnecting");
if (reds->config->sasl_enabled) {
spice_warning("Your client doesn't handle SASL?");
}
reds_send_link_error(link, SPICE_LINK_ERR_INVALID_DATA);
reds_link_free(link);
}
}