mirror of
https://github.com/strongswan/strongswan.git
synced 2025-11-27 00:00:29 -05:00
Implemented a tls_writer class to simplify TLS data generation
This commit is contained in:
parent
4ef946dd64
commit
3a1640dea1
@ -12,6 +12,7 @@ libstrongswan_eap_tls_la_SOURCES = eap_tls_plugin.h eap_tls_plugin.c \
|
||||
tls/tls_fragmentation.h tls/tls_fragmentation.c \
|
||||
tls/tls_crypto.h tls/tls_crypto.c \
|
||||
tls/tls_reader.h tls/tls_reader.c \
|
||||
tls/tls_writer.h tls/tls_writer.c \
|
||||
tls/tls_peer.h tls/tls_peer.c \
|
||||
tls/tls_server.h tls/tls_server.c \
|
||||
tls/tls_handshake.h
|
||||
|
||||
@ -50,6 +50,11 @@ struct private_tls_fragmentation_t {
|
||||
* Currently processed handshake message type
|
||||
*/
|
||||
tls_handshake_type_t type;
|
||||
|
||||
/**
|
||||
* Handshake output buffer
|
||||
*/
|
||||
chunk_t output;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -62,15 +67,6 @@ struct private_tls_fragmentation_t {
|
||||
*/
|
||||
#define MAX_TLS_HANDSHAKE_LEN 65536
|
||||
|
||||
/**
|
||||
* TLS handshake message header
|
||||
*/
|
||||
typedef union {
|
||||
u_int8_t type;
|
||||
/* 24bit length field */
|
||||
u_int32_t length;
|
||||
} tls_handshake_header_t;
|
||||
|
||||
/**
|
||||
* Process TLS handshake protocol data
|
||||
*/
|
||||
@ -171,27 +167,61 @@ METHOD(tls_fragmentation_t, process, status_t,
|
||||
METHOD(tls_fragmentation_t, build, status_t,
|
||||
private_tls_fragmentation_t *this, tls_content_type_t *type, chunk_t *data)
|
||||
{
|
||||
tls_handshake_header_t header;
|
||||
tls_handshake_type_t hs_type;
|
||||
chunk_t hs_data;
|
||||
tls_writer_t *writer, *msg;
|
||||
status_t status;
|
||||
|
||||
status = this->handshake->build(this->handshake, &hs_type, &hs_data);
|
||||
if (status != NEED_MORE)
|
||||
if (!this->output.len)
|
||||
{
|
||||
msg = tls_writer_create(64);
|
||||
do
|
||||
{
|
||||
writer = tls_writer_create(64);
|
||||
status = this->handshake->build(this->handshake, &hs_type, writer);
|
||||
switch (status)
|
||||
{
|
||||
case NEED_MORE:
|
||||
msg->write_uint8(msg, hs_type);
|
||||
msg->write_data24(msg, writer->get_buf(writer));
|
||||
break;
|
||||
case INVALID_STATE:
|
||||
this->output = chunk_clone(msg->get_buf(msg));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
writer->destroy(writer);
|
||||
}
|
||||
while (status == NEED_MORE);
|
||||
|
||||
msg->destroy(msg);
|
||||
if (status != INVALID_STATE)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
htoun32(&header.length, hs_data.len);
|
||||
header.type |= hs_type;
|
||||
*data = chunk_cat("cm", chunk_from_thing(header), hs_data);
|
||||
}
|
||||
|
||||
if (this->output.len)
|
||||
{
|
||||
*type = TLS_HANDSHAKE;
|
||||
if (this->output.len <= MAX_TLS_FRAGMENT_LEN)
|
||||
{
|
||||
*data = this->output;
|
||||
this->output = chunk_empty;
|
||||
return NEED_MORE;
|
||||
}
|
||||
*data = chunk_create(this->output.ptr, MAX_TLS_FRAGMENT_LEN);
|
||||
this->output = chunk_clone(chunk_skip(this->output, MAX_TLS_FRAGMENT_LEN));
|
||||
return NEED_MORE;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
METHOD(tls_fragmentation_t, destroy, void,
|
||||
private_tls_fragmentation_t *this)
|
||||
{
|
||||
free(this->input.ptr);
|
||||
free(this->output.ptr);
|
||||
free(this);
|
||||
}
|
||||
|
||||
|
||||
@ -25,6 +25,7 @@ typedef struct tls_handshake_t tls_handshake_t;
|
||||
|
||||
#include "tls.h"
|
||||
#include "tls_reader.h"
|
||||
#include "tls_writer.h"
|
||||
|
||||
/**
|
||||
* TLS handshake state machine interface.
|
||||
@ -48,7 +49,7 @@ struct tls_handshake_t {
|
||||
* Build TLS handshake messages to send out.
|
||||
*
|
||||
* @param type type of created handshake message
|
||||
* @param data allocated TLS handshake message data
|
||||
* @param writer TLS data buffer to write to
|
||||
* @return
|
||||
* - SUCCESS if handshake complete
|
||||
* - FAILED if handshake failed
|
||||
@ -56,7 +57,7 @@ struct tls_handshake_t {
|
||||
* - INVALID_STATE if more input to process() required
|
||||
*/
|
||||
status_t (*build)(tls_handshake_t *this,
|
||||
tls_handshake_type_t *type, chunk_t *data);
|
||||
tls_handshake_type_t *type, tls_writer_t *writer);
|
||||
|
||||
/**
|
||||
* Destroy a tls_handshake_t.
|
||||
|
||||
@ -185,82 +185,54 @@ METHOD(tls_handshake_t, process, status_t,
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Client Hello using a given set of ciphers
|
||||
*/
|
||||
static chunk_t build_hello(private_tls_peer_t *this,
|
||||
int count, tls_cipher_suite_t *suite, rng_t *rng)
|
||||
{
|
||||
int i;
|
||||
|
||||
struct __attribute__((packed)) {
|
||||
u_int16_t version;
|
||||
struct __attribute__((packed)) {
|
||||
u_int32_t gmt;
|
||||
u_int8_t bytes[28];
|
||||
} random;
|
||||
struct __attribute__((packed)) {
|
||||
/* never send a session identifier */
|
||||
u_int8_t len;
|
||||
u_int8_t id[0];
|
||||
} session;
|
||||
struct __attribute__((packed)) {
|
||||
u_int16_t len;
|
||||
u_int16_t suite[count];
|
||||
} cipher;
|
||||
struct __attribute__((packed)) {
|
||||
/* currently NULL compression only */
|
||||
u_int8_t len;
|
||||
u_int8_t method[1];
|
||||
} compression;
|
||||
u_int8_t extensions[0];
|
||||
} hello;
|
||||
|
||||
htoun16(&hello.session.len, 0);
|
||||
htoun16(&hello.version, this->tls->get_version(this->tls));
|
||||
htoun32(&hello.random.gmt, time(NULL));
|
||||
rng->get_bytes(rng, sizeof(hello.random.bytes), (char*)&hello.random.bytes);
|
||||
htoun16(&hello.cipher.len, count * 2);
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
htoun16(&hello.cipher.suite[i], suite[i]);
|
||||
}
|
||||
hello.compression.len = 1;
|
||||
hello.compression.method[0] = 0;
|
||||
return chunk_clone(chunk_create((char*)&hello, sizeof(hello)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a client hello
|
||||
*/
|
||||
static status_t send_hello(private_tls_peer_t *this,
|
||||
tls_handshake_type_t *type, chunk_t *data)
|
||||
tls_handshake_type_t *type, tls_writer_t *writer)
|
||||
{
|
||||
tls_cipher_suite_t *suite;
|
||||
int count;
|
||||
int count, i;
|
||||
rng_t *rng;
|
||||
char random[28];
|
||||
|
||||
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
|
||||
if (!rng)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
count = this->crypto->get_cipher_suites(this->crypto, &suite);
|
||||
*data = build_hello(this, count, suite, rng);
|
||||
*type = TLS_CLIENT_HELLO;
|
||||
free(suite);
|
||||
rng->get_bytes(rng, sizeof(random), random);
|
||||
rng->destroy(rng);
|
||||
|
||||
writer->write_uint16(writer, this->tls->get_version(this->tls));
|
||||
writer->write_uint32(writer, time(NULL));
|
||||
writer->write_data(writer, chunk_from_thing(random));
|
||||
/* session identifier => none */
|
||||
writer->write_data8(writer, chunk_empty);
|
||||
|
||||
count = this->crypto->get_cipher_suites(this->crypto, &suite);
|
||||
writer->write_uint16(writer, count * 2);
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
writer->write_uint16(writer, suite[i]);
|
||||
}
|
||||
free(suite);
|
||||
/* NULL compression only */
|
||||
writer->write_uint8(writer, 1);
|
||||
writer->write_uint8(writer, 0);
|
||||
|
||||
*type = TLS_CLIENT_HELLO;
|
||||
this->state = STATE_HELLO_SENT;
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
METHOD(tls_handshake_t, build, status_t,
|
||||
private_tls_peer_t *this, tls_handshake_type_t *type, chunk_t *data)
|
||||
private_tls_peer_t *this, tls_handshake_type_t *type, tls_writer_t *writer)
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case STATE_INIT:
|
||||
return send_hello(this, type, data);
|
||||
return send_hello(this, type, writer);
|
||||
default:
|
||||
return INVALID_STATE;
|
||||
}
|
||||
|
||||
@ -48,7 +48,7 @@ METHOD(tls_handshake_t, process, status_t,
|
||||
}
|
||||
|
||||
METHOD(tls_handshake_t, build, status_t,
|
||||
private_tls_server_t *this, tls_handshake_type_t *type, chunk_t *data)
|
||||
private_tls_server_t *this, tls_handshake_type_t *type, tls_writer_t *writer)
|
||||
{
|
||||
return INVALID_STATE;
|
||||
}
|
||||
|
||||
237
src/charon/plugins/eap_tls/tls/tls_writer.c
Normal file
237
src/charon/plugins/eap_tls/tls/tls_writer.c
Normal file
@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "tls_writer.h"
|
||||
|
||||
typedef struct private_tls_writer_t private_tls_writer_t;
|
||||
|
||||
/**
|
||||
* Private data of an tls_writer_t object.
|
||||
*/
|
||||
struct private_tls_writer_t {
|
||||
|
||||
/**
|
||||
* Public tls_writer_t interface.
|
||||
*/
|
||||
tls_writer_t public;
|
||||
|
||||
/**
|
||||
* Allocated buffer
|
||||
*/
|
||||
chunk_t buf;
|
||||
|
||||
/**
|
||||
* Used bytes in buffer
|
||||
*/
|
||||
size_t used;
|
||||
|
||||
/**
|
||||
* Number of bytes to increase buffer size
|
||||
*/
|
||||
size_t increase;
|
||||
};
|
||||
|
||||
/**
|
||||
* Increase buffer size
|
||||
*/
|
||||
static void increase(private_tls_writer_t *this)
|
||||
{
|
||||
this->buf.len += this->increase;
|
||||
this->buf.ptr = realloc(this->buf.ptr, this->buf.len);
|
||||
}
|
||||
|
||||
METHOD(tls_writer_t, write_uint8, void,
|
||||
private_tls_writer_t *this, u_int8_t value)
|
||||
{
|
||||
if (this->used + 1 > this->buf.len)
|
||||
{
|
||||
increase(this);
|
||||
}
|
||||
this->buf.ptr[this->used] = value;
|
||||
this->used += 1;
|
||||
}
|
||||
|
||||
METHOD(tls_writer_t, write_uint16, void,
|
||||
private_tls_writer_t *this, u_int16_t value)
|
||||
{
|
||||
if (this->used + 2 > this->buf.len)
|
||||
{
|
||||
increase(this);
|
||||
}
|
||||
htoun16(this->buf.ptr + this->used, value);
|
||||
this->used += 2;
|
||||
}
|
||||
|
||||
METHOD(tls_writer_t, write_uint24, void,
|
||||
private_tls_writer_t *this, u_int32_t value)
|
||||
{
|
||||
if (this->used + 3 > this->buf.len)
|
||||
{
|
||||
increase(this);
|
||||
}
|
||||
value = htonl(value);
|
||||
memcpy(this->buf.ptr + this->used, ((char*)&value) + 1, 3);
|
||||
this->used += 3;
|
||||
}
|
||||
|
||||
METHOD(tls_writer_t, write_uint32, void,
|
||||
private_tls_writer_t *this, u_int32_t value)
|
||||
{
|
||||
if (this->used + 4 > this->buf.len)
|
||||
{
|
||||
increase(this);
|
||||
}
|
||||
htoun32(this->buf.ptr + this->used, value);
|
||||
this->used += 4;
|
||||
}
|
||||
|
||||
METHOD(tls_writer_t, write_data, void,
|
||||
private_tls_writer_t *this, chunk_t value)
|
||||
{
|
||||
while (this->used + value.len > this->buf.len)
|
||||
{
|
||||
increase(this);
|
||||
}
|
||||
memcpy(this->buf.ptr + this->used, value.ptr, value.len);
|
||||
this->used += value.len;
|
||||
}
|
||||
|
||||
METHOD(tls_writer_t, write_data8, void,
|
||||
private_tls_writer_t *this, chunk_t value)
|
||||
{
|
||||
write_uint8(this, value.len);
|
||||
write_data(this, value);
|
||||
}
|
||||
|
||||
METHOD(tls_writer_t, write_data16, void,
|
||||
private_tls_writer_t *this, chunk_t value)
|
||||
{
|
||||
write_uint16(this, value.len);
|
||||
write_data(this, value);
|
||||
}
|
||||
|
||||
METHOD(tls_writer_t, write_data24, void,
|
||||
private_tls_writer_t *this, chunk_t value)
|
||||
{
|
||||
write_uint24(this, value.len);
|
||||
write_data(this, value);
|
||||
}
|
||||
|
||||
METHOD(tls_writer_t, write_data32, void,
|
||||
private_tls_writer_t *this, chunk_t value)
|
||||
{
|
||||
write_uint32(this, value.len);
|
||||
write_data(this, value);
|
||||
}
|
||||
|
||||
METHOD(tls_writer_t, wrap8, void,
|
||||
private_tls_writer_t *this)
|
||||
{
|
||||
if (this->used + 1 > this->buf.len)
|
||||
{
|
||||
increase(this);
|
||||
}
|
||||
memmove(this->buf.ptr + 1, this->buf.ptr, 1);
|
||||
this->buf.ptr[0] = this->used;
|
||||
this->used += 1;
|
||||
}
|
||||
|
||||
METHOD(tls_writer_t, wrap16, void,
|
||||
private_tls_writer_t *this)
|
||||
{
|
||||
if (this->used + 2 > this->buf.len)
|
||||
{
|
||||
increase(this);
|
||||
}
|
||||
memmove(this->buf.ptr + 2, this->buf.ptr, 2);
|
||||
htoun16(this->buf.ptr, this->used);
|
||||
this->used += 2;
|
||||
}
|
||||
|
||||
METHOD(tls_writer_t, wrap24, void,
|
||||
private_tls_writer_t *this)
|
||||
{
|
||||
u_int32_t len;
|
||||
|
||||
if (this->used + 3 > this->buf.len)
|
||||
{
|
||||
increase(this);
|
||||
}
|
||||
memmove(this->buf.ptr + 3, this->buf.ptr, 3);
|
||||
|
||||
len = htonl(this->used);
|
||||
memcpy(this->buf.ptr, ((char*)&len) + 1, 3);
|
||||
this->used += 3;
|
||||
}
|
||||
|
||||
METHOD(tls_writer_t, wrap32, void,
|
||||
private_tls_writer_t *this)
|
||||
{
|
||||
if (this->used + 4 > this->buf.len)
|
||||
{
|
||||
increase(this);
|
||||
}
|
||||
memmove(this->buf.ptr + 4, this->buf.ptr, 4);
|
||||
htoun32(this->buf.ptr, this->used);
|
||||
this->used += 4;
|
||||
}
|
||||
|
||||
METHOD(tls_writer_t, get_buf, chunk_t,
|
||||
private_tls_writer_t *this)
|
||||
{
|
||||
return chunk_create(this->buf.ptr, this->used);
|
||||
}
|
||||
|
||||
METHOD(tls_writer_t, destroy, void,
|
||||
private_tls_writer_t *this)
|
||||
{
|
||||
free(this->buf.ptr);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* See header
|
||||
*/
|
||||
tls_writer_t *tls_writer_create(u_int32_t bufsize)
|
||||
{
|
||||
private_tls_writer_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.write_uint8 = _write_uint8,
|
||||
.write_uint16 = _write_uint16,
|
||||
.write_uint24 = _write_uint24,
|
||||
.write_uint32 = _write_uint32,
|
||||
.write_data = _write_data,
|
||||
.write_data8 = _write_data8,
|
||||
.write_data16 = _write_data16,
|
||||
.write_data24 = _write_data24,
|
||||
.write_data32 = _write_data32,
|
||||
.wrap8 = _wrap8,
|
||||
.wrap16 = _wrap16,
|
||||
.wrap24 = _wrap24,
|
||||
.wrap32 = _wrap32,
|
||||
.get_buf = _get_buf,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.increase = bufsize ?: 32,
|
||||
);
|
||||
if (bufsize)
|
||||
{
|
||||
this->buf = chunk_alloc(bufsize);
|
||||
}
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
136
src/charon/plugins/eap_tls/tls/tls_writer.h
Normal file
136
src/charon/plugins/eap_tls/tls/tls_writer.h
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup tls_writer tls_writer
|
||||
* @{ @ingroup tls
|
||||
*/
|
||||
|
||||
#ifndef TLS_WRITER_H_
|
||||
#define TLS_WRITER_H_
|
||||
|
||||
typedef struct tls_writer_t tls_writer_t;
|
||||
|
||||
#include <library.h>
|
||||
|
||||
/**
|
||||
* TLS record generator.
|
||||
*/
|
||||
struct tls_writer_t {
|
||||
|
||||
/**
|
||||
* Append a 8-bit integer to the buffer.
|
||||
*
|
||||
* @param value value to append
|
||||
*/
|
||||
void (*write_uint8)(tls_writer_t *this, u_int8_t value);
|
||||
|
||||
/**
|
||||
* Append a 16-bit integer to the buffer.
|
||||
*
|
||||
* @param value value to append
|
||||
*/
|
||||
void (*write_uint16)(tls_writer_t *this, u_int16_t value);
|
||||
|
||||
/**
|
||||
* Append a 24-bit integer to the buffer.
|
||||
*
|
||||
* @param value value to append
|
||||
*/
|
||||
void (*write_uint24)(tls_writer_t *this, u_int32_t value);
|
||||
|
||||
/**
|
||||
* Append a 32-bit integer to the buffer.
|
||||
*
|
||||
* @param value value to append
|
||||
*/
|
||||
void (*write_uint32)(tls_writer_t *this, u_int32_t value);
|
||||
|
||||
/**
|
||||
* Append a chunk of data without a length header.
|
||||
*
|
||||
* @param value value to append
|
||||
*/
|
||||
void (*write_data)(tls_writer_t *this, chunk_t value);
|
||||
|
||||
/**
|
||||
* Append a chunk of data with a 16-bit length header.
|
||||
*
|
||||
* @param value value to append
|
||||
*/
|
||||
void (*write_data8)(tls_writer_t *this, chunk_t value);
|
||||
|
||||
/**
|
||||
* Append a chunk of data with a 8-bit length header.
|
||||
*
|
||||
* @param value value to append
|
||||
*/
|
||||
void (*write_data16)(tls_writer_t *this, chunk_t value);
|
||||
|
||||
/**
|
||||
* Append a chunk of data with a 24-bit length header.
|
||||
*
|
||||
* @param value value to append
|
||||
*/
|
||||
void (*write_data24)(tls_writer_t *this, chunk_t value);
|
||||
|
||||
/**
|
||||
* Append a chunk of data with a 32-bit length header.
|
||||
*
|
||||
* @param value value to append
|
||||
*/
|
||||
void (*write_data32)(tls_writer_t *this, chunk_t value);
|
||||
|
||||
/**
|
||||
* Prepend a 8-bit length header to existing data.
|
||||
*/
|
||||
void (*wrap8)(tls_writer_t *this);
|
||||
|
||||
/**
|
||||
* Prepend a 16-bit length header to existing data.
|
||||
*/
|
||||
void (*wrap16)(tls_writer_t *this);
|
||||
|
||||
/**
|
||||
* Prepend a 24-bit length header to existing data.
|
||||
*/
|
||||
void (*wrap24)(tls_writer_t *this);
|
||||
|
||||
/**
|
||||
* Prepend a 32-bit length header to existing data.
|
||||
*/
|
||||
void (*wrap32)(tls_writer_t *this);
|
||||
|
||||
/**
|
||||
* Get the encoded data buffer.
|
||||
*
|
||||
* @return chunk to internal buffer
|
||||
*/
|
||||
chunk_t (*get_buf)(tls_writer_t *this);
|
||||
|
||||
/**
|
||||
* Destroy a tls_writer_t.
|
||||
*/
|
||||
void (*destroy)(tls_writer_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a tls_writer instance.
|
||||
*
|
||||
* @param bufsize initially allocated buffer size
|
||||
*/
|
||||
tls_writer_t *tls_writer_create(u_int32_t bufsize);
|
||||
|
||||
#endif /** TLS_WRITER_H_ @}*/
|
||||
Loading…
x
Reference in New Issue
Block a user