Implement SASL authentication in PT-TLS client
This commit is contained in:
parent
3542c4f18a
commit
66d8fd690c
|
@ -16,6 +16,8 @@
|
|||
#include "pt_tls_client.h"
|
||||
#include "pt_tls.h"
|
||||
|
||||
#include <sasl/sasl_mechanism.h>
|
||||
|
||||
#include <tls_socket.h>
|
||||
#include <utils/debug.h>
|
||||
|
||||
|
@ -133,33 +135,211 @@ static bool negotiate_version(private_pt_tls_client_t *this)
|
|||
}
|
||||
|
||||
/**
|
||||
* Authenticate session using SASL
|
||||
* Run a SASL mechanism
|
||||
*/
|
||||
static bool authenticate(private_pt_tls_client_t *this)
|
||||
static status_t do_sasl(private_pt_tls_client_t *this, sasl_mechanism_t *sasl)
|
||||
{
|
||||
u_int32_t type, vendor, identifier;
|
||||
u_int8_t result;
|
||||
bio_reader_t *reader;
|
||||
bio_writer_t *writer;
|
||||
chunk_t data;
|
||||
|
||||
writer = bio_writer_create(32);
|
||||
writer->write_data8(writer, chunk_from_str(sasl->get_name(sasl)));
|
||||
switch (sasl->build(sasl, &data))
|
||||
{
|
||||
case INVALID_STATE:
|
||||
break;
|
||||
case NEED_MORE:
|
||||
writer->write_data(writer, data);
|
||||
free(data.ptr);
|
||||
break;
|
||||
case SUCCESS:
|
||||
/* shouldn't happen */
|
||||
free(data.ptr);
|
||||
/* FALL */
|
||||
case FAILED:
|
||||
default:
|
||||
writer->destroy(writer);
|
||||
return FAILED;
|
||||
}
|
||||
if (!pt_tls_write(this->tls, writer, PT_TLS_SASL_MECH_SELECTION,
|
||||
this->identifier++))
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
while (TRUE)
|
||||
{
|
||||
reader = pt_tls_read(this->tls, &vendor, &type, &identifier);
|
||||
if (!reader)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
if (vendor != 0)
|
||||
{
|
||||
reader->destroy(reader);
|
||||
return FAILED;
|
||||
}
|
||||
switch (type)
|
||||
{
|
||||
case PT_TLS_SASL_AUTH_DATA:
|
||||
switch (sasl->process(sasl, reader->peek(reader)))
|
||||
{
|
||||
case NEED_MORE:
|
||||
reader->destroy(reader);
|
||||
break;
|
||||
case SUCCESS:
|
||||
/* should not happen, as it would come in a RESULT */
|
||||
case FAILED:
|
||||
default:
|
||||
reader->destroy(reader);
|
||||
return FAILED;
|
||||
}
|
||||
break;
|
||||
case PT_TLS_SASL_RESULT:
|
||||
if (!reader->read_uint8(reader, &result))
|
||||
{
|
||||
reader->destroy(reader);
|
||||
return FAILED;
|
||||
}
|
||||
switch (result)
|
||||
{
|
||||
case PT_TLS_SASL_RESULT_ABORT:
|
||||
DBG1(DBG_TNC, "received SASL abort result");
|
||||
reader->destroy(reader);
|
||||
return FAILED;
|
||||
case PT_TLS_SASL_RESULT_SUCCESS:
|
||||
DBG1(DBG_TNC, "received SASL success result");
|
||||
switch (sasl->process(sasl, reader->peek(reader)))
|
||||
{
|
||||
case SUCCESS:
|
||||
reader->destroy(reader);
|
||||
return SUCCESS;
|
||||
case NEED_MORE:
|
||||
/* inacceptable, it won't get more. FALL */
|
||||
case FAILED:
|
||||
default:
|
||||
reader->destroy(reader);
|
||||
return FAILED;
|
||||
}
|
||||
break;
|
||||
case PT_TLS_SASL_RESULT_MECH_FAILURE:
|
||||
case PT_TLS_SASL_RESULT_FAILURE:
|
||||
DBG1(DBG_TNC, "received SASL failure result");
|
||||
/* non-fatal failure, try again */
|
||||
reader->destroy(reader);
|
||||
return NEED_MORE;
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
writer = bio_writer_create(32);
|
||||
switch (sasl->build(sasl, &data))
|
||||
{
|
||||
case INVALID_STATE:
|
||||
break;
|
||||
case SUCCESS:
|
||||
/* shoudln't happen, continue until we get a result */
|
||||
case NEED_MORE:
|
||||
writer->write_data(writer, data);
|
||||
free(data.ptr);
|
||||
break;
|
||||
case FAILED:
|
||||
default:
|
||||
writer->destroy(writer);
|
||||
return FAILED;
|
||||
}
|
||||
if (!pt_tls_write(this->tls, writer, PT_TLS_SASL_AUTH_DATA,
|
||||
this->identifier++))
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read SASL mechanism list, select and run mechanism
|
||||
*/
|
||||
static status_t select_and_do_sasl(private_pt_tls_client_t *this)
|
||||
{
|
||||
bio_reader_t *reader;
|
||||
sasl_mechanism_t *sasl = NULL;
|
||||
u_int32_t type, vendor, identifier;
|
||||
u_int8_t len;
|
||||
chunk_t chunk;
|
||||
char buf[21];
|
||||
status_t status = NEED_MORE;
|
||||
|
||||
reader = pt_tls_read(this->tls, &vendor, &type, &identifier);
|
||||
if (!reader)
|
||||
{
|
||||
return FALSE;
|
||||
return FAILED;
|
||||
}
|
||||
if (vendor != 0 || type != PT_TLS_SASL_MECHS)
|
||||
{
|
||||
DBG1(DBG_TNC, "PT-TLS authentication failed");
|
||||
reader->destroy(reader);
|
||||
return FALSE;
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
if (reader->remaining(reader))
|
||||
{ /* mechanism list not empty, FAIL until we support it */
|
||||
if (!reader->remaining(reader))
|
||||
{ /* mechanism list empty, SASL completed */
|
||||
DBG1(DBG_TNC, "PT-TLS authentication complete");
|
||||
reader->destroy(reader);
|
||||
return FALSE;
|
||||
return SUCCESS;
|
||||
}
|
||||
while (reader->remaining(reader))
|
||||
{
|
||||
if (!reader->read_uint8(reader, &len) ||
|
||||
!reader->read_data(reader, len & 0x1F, &chunk))
|
||||
{
|
||||
reader->destroy(reader);
|
||||
return FAILED;
|
||||
}
|
||||
snprintf(buf, sizeof(buf), "%.*s", (int)chunk.len, chunk.ptr);
|
||||
sasl = sasl_mechanism_create(buf, this->client);
|
||||
if (sasl)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
DBG1(DBG_TNC, "PT-TLS authentication complete");
|
||||
reader->destroy(reader);
|
||||
return TRUE;
|
||||
|
||||
if (!sasl)
|
||||
{
|
||||
/* TODO: send PT-TLS error (5) */
|
||||
return FAILED;
|
||||
}
|
||||
while (status == NEED_MORE)
|
||||
{
|
||||
status = do_sasl(this, sasl);
|
||||
}
|
||||
sasl->destroy(sasl);
|
||||
if (status == SUCCESS)
|
||||
{ /* continue until we receive empty SASL mechanism list */
|
||||
return NEED_MORE;
|
||||
}
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate session using SASL
|
||||
*/
|
||||
static bool authenticate(private_pt_tls_client_t *this)
|
||||
{
|
||||
while (TRUE)
|
||||
{
|
||||
switch (select_and_do_sasl(this))
|
||||
{
|
||||
case NEED_MORE:
|
||||
continue;
|
||||
case SUCCESS:
|
||||
return TRUE;
|
||||
case FAILED:
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue