- IEC 61850/MMS: integrated TLS for MMS client/server

pull/143/head
Michael Zillgith 8 years ago
parent 9c946eeb40
commit 570ca71570

@ -69,6 +69,7 @@ include_directories(
src/mms/inc_private
src/mms/iso_mms/asn1c
src/logging
src/tls
)
set(API_HEADERS
@ -110,6 +111,7 @@ set(API_HEADERS
src/sampled_values/sv_publisher_deprecated.h
src/sampled_values/sv_subscriber_deprecated.h
src/logging/logging_api.h
src/tls/tls_api.h
${CMAKE_CURRENT_BINARY_DIR}/config/stack_config.h
)
@ -119,6 +121,23 @@ if(MSVC)
)
endif(MSVC)
if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.6.0)
set(WITH_MBEDTLS 1)
endif(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.6.0)
if(WITH_MBEDTLS)
include_directories(
src/tls/mbedtls
third_party/mbedtls/mbedtls-2.6.0/include
)
file(GLOB tls_SRCS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.6.0/library/*.c)
add_definitions(-DCONFIG_MMS_SUPPORT_TLS=1)
add_definitions(-DMBEDTLS_CONFIG_FILE="mbedtls_config.h")
endif(WITH_MBEDTLS)
# write the detected stuff to this file
configure_file(
${CMAKE_CURRENT_LIST_DIR}/config/stack_config.h.cmake

@ -60,10 +60,20 @@ LIB_INCLUDE_DIRS += src/sampled_values
LIB_INCLUDE_DIRS += src/iec61850/inc
LIB_INCLUDE_DIRS += src/iec61850/inc_private
LIB_INCLUDE_DIRS += src/logging
LIB_INCLUDE_DIRS += src/tls
ifeq ($(HAL_IMPL), WIN32)
LIB_INCLUDE_DIRS += third_party/winpcap/Include
endif
ifdef WITH_MBEDTLS
LIB_SOURCE_DIRS += third_party/mbedtls/mbedtls-2.6.0/library
LIB_SOURCE_DIRS += src/tls/mbedtls
LIB_INCLUDE_DIRS += third_party/mbedtls/mbedtls-2.6.0/include
LIB_INCLUDE_DIRS += src/tls/mbedtls
MBEDTLS_CONFIG_FILE = "mbedtls_config.h"
CFLAGS += -D'CONFIG_MMS_SUPPORT_TLS=1'
endif
LIB_INCLUDES = $(addprefix -I,$(LIB_INCLUDE_DIRS))
ifndef INSTALL_PREFIX
@ -102,6 +112,7 @@ LIB_API_HEADER_FILES += src/goose/goose_publisher.h
LIB_API_HEADER_FILES += src/sampled_values/sv_subscriber.h
LIB_API_HEADER_FILES += src/sampled_values/sv_publisher.h
LIB_API_HEADER_FILES += src/logging/logging_api.h
LIB_API_HEADER_FILES += src/tls/tls_api.h
get_sources_from_directory = $(wildcard $1/*.c)
get_sources = $(foreach dir, $1, $(call get_sources_from_directory,$(dir)))

@ -9,3 +9,4 @@ INCLUDES += -I$(LIBIEC_HOME)/src/hal/inc
INCLUDES += -I$(LIBIEC_HOME)/src/goose
INCLUDES += -I$(LIBIEC_HOME)/src/sampled_values
INCLUDES += -I$(LIBIEC_HOME)/src/logging
INCLUDES += -I$(LIBIEC_HOME)/src/tls

@ -80,6 +80,15 @@ set (lib_common_SRCS
./logging/log_storage.c
)
if(WITH_MBEDTLS)
set (lib_common_SRCS ${lib_common_SRCS}
./tls/mbedtls/tls_mbedtls.c
)
list (APPEND lib_common_SRCS ${tls_SRCS})
endif(WITH_MBEDTLS)
set (lib_asn1c_SRCS
./mms/iso_mms/asn1c/DataAccessError.c
./mms/iso_mms/asn1c/DeleteNamedVariableListRequest.c

@ -61,12 +61,23 @@ typedef struct sClientConnection* ClientConnection;
/**
* \brief Create a new IedServer instance
*
* \param iedModel reference to the IedModel data structure to be used as IEC 61850 model of the device
* \param dataModel reference to the IedModel data structure to be used as IEC 61850 data model of the device
*
* \return the newly generated IedServer instance
* \return the new IedServer instance
*/
IedServer
IedServer_create(IedModel* iedModel);
IedServer_create(IedModel* dataModel);
/**
* \brief Create a new IedServer with TLS support
*
* \param dataModel reference to the IedModel data structure to be used as IEC 61850 data model of the device
* \param tlsConfiguration TLS configuration object, or NULL to not use TLS
*
* \return the new IedServer instance
*/
IedServer
IedServer_createWithTlsSupport(IedModel* dataModel, TLSConfiguration tlsConfiguration);
/**
* \brief Destroy an IedServer instance and release all resources (memory, TCP sockets)
@ -208,16 +219,6 @@ IedServer_isRunning(IedServer self);
MmsServer
IedServer_getMmsServer(IedServer self);
/**
* \brief get the IsoServer instance for this IedServer object
*
* \param self the instance of IedServer to operate on.
*
* \return the IsoServer instance of this IedServer object
*/
IsoServer
IedServer_getIsoServer(IedServer self);
/**
* \brief Enable all GOOSE control blocks.
*

@ -38,7 +38,7 @@ struct sIedServer
IedModel* model;
MmsDevice* mmsDevice;
MmsServer mmsServer;
IsoServer isoServer;
// IsoServer isoServer;
char* localIpAddress;
MmsMapping* mmsMapping;
LinkedList clientConnections;

@ -398,57 +398,66 @@ updateDataSetsWithCachedValues(IedServer self)
}
IedServer
IedServer_create(IedModel* iedModel)
IedServer_createWithTlsSupport(IedModel* dataModel, TLSConfiguration tlsConfiguration)
{
IedServer self = (IedServer) GLOBAL_CALLOC(1, sizeof(struct sIedServer));
self->model = iedModel;
if (self) {
// self->running = false; /* not required due to CALLOC */
// self->localIpAddress = NULL; /* not required due to CALLOC */
self->model = dataModel;
self->running = false;
self->localIpAddress = NULL;
#if (CONFIG_MMS_THREADLESS_STACK != 1)
self->dataModelLock = Semaphore_create(1);
self->dataModelLock = Semaphore_create(1);
#endif
self->mmsMapping = MmsMapping_create(iedModel);
self->mmsMapping = MmsMapping_create(dataModel);
self->mmsDevice = MmsMapping_getMmsDeviceModel(self->mmsMapping);
self->mmsDevice = MmsMapping_getMmsDeviceModel(self->mmsMapping);
self->isoServer = IsoServer_create();
// self->isoServer = IsoServer_create();
self->mmsServer = MmsServer_create(self->isoServer, self->mmsDevice);
self->mmsServer = MmsServer_create(self->mmsDevice, tlsConfiguration);
MmsMapping_setMmsServer(self->mmsMapping, self->mmsServer);
MmsMapping_setMmsServer(self->mmsMapping, self->mmsServer);
MmsMapping_installHandlers(self->mmsMapping);
MmsMapping_installHandlers(self->mmsMapping);
MmsMapping_setIedServer(self->mmsMapping, self);
MmsMapping_setIedServer(self->mmsMapping, self);
createMmsServerCache(self);
createMmsServerCache(self);
iedModel->initializer();
dataModel->initializer();
installDefaultValuesInCache(self); /* This will also connect cached MmsValues to DataAttributes */
installDefaultValuesInCache(self); /* This will also connect cached MmsValues to DataAttributes */
updateDataSetsWithCachedValues(self);
updateDataSetsWithCachedValues(self);
self->clientConnections = LinkedList_create();
self->clientConnections = LinkedList_create();
/* default write access policy allows access to SP, SE and SV FCDAs but denies access to DC and CF FCDAs */
self->writeAccessPolicies = ALLOW_WRITE_ACCESS_SP | ALLOW_WRITE_ACCESS_SV | ALLOW_WRITE_ACCESS_SE;
/* default write access policy allows access to SP, SE and SV FCDAs but denies access to DC and CF FCDAs */
self->writeAccessPolicies = ALLOW_WRITE_ACCESS_SP | ALLOW_WRITE_ACCESS_SV | ALLOW_WRITE_ACCESS_SE;
#if (CONFIG_IEC61850_REPORT_SERVICE == 1)
Reporting_activateBufferedReports(self->mmsMapping);
Reporting_activateBufferedReports(self->mmsMapping);
#endif
#if (CONFIG_IEC61850_SETTING_GROUPS == 1)
MmsMapping_configureSettingGroups(self->mmsMapping);
MmsMapping_configureSettingGroups(self->mmsMapping);
#endif
}
return self;
}
IedServer
IedServer_create(IedModel* dataModel)
{
return IedServer_createWithTlsSupport(dataModel, NULL);
}
void
IedServer_destroy(IedServer self)
{
@ -463,7 +472,6 @@ IedServer_destroy(IedServer self)
}
MmsServer_destroy(self->mmsServer);
IsoServer_destroy(self->isoServer);
if (self->localIpAddress != NULL)
GLOBAL_FREEMEM(self->localIpAddress);
@ -505,12 +513,6 @@ IedServer_getMmsServer(IedServer self)
return self->mmsServer;
}
IsoServer
IedServer_getIsoServer(IedServer self)
{
return self->isoServer;
}
#if (CONFIG_MMS_THREADLESS_STACK != 1)
#if (CONFIG_MMS_SINGLE_THREADED == 1)
static void
@ -574,10 +576,7 @@ IedServer_start(IedServer self, int tcpPort)
bool
IedServer_isRunning(IedServer self)
{
if (IsoServer_getState(self->isoServer) == ISO_SVR_STATE_RUNNING)
return true;
else
return false;
return MmsServer_isRunning(self->mmsServer);
}
IedModel*
@ -618,7 +617,8 @@ IedServer_setLocalIpAddress(IedServer self, const char* localIpAddress)
GLOBAL_FREEMEM(self->localIpAddress);
self->localIpAddress = StringUtils_copyString(localIpAddress);
IsoServer_setLocalIpAddress(self->isoServer, self->localIpAddress);
MmsServer_setLocalIpAddress(self->mmsServer, self->localIpAddress);
}

@ -28,6 +28,8 @@
extern "C" {
#endif
#include "tls_api.h"
/**
* \addtogroup mms_client_api_group
*/
@ -39,8 +41,13 @@ extern "C" {
*/
typedef enum
{
/** Neither ACSE nor TLS authentication used */
ACSE_AUTH_NONE = 0,
/** Use ACSE password for client authentication */
ACSE_AUTH_PASSWORD = 1,
/** Use ACSE certificate for client authentication */
ACSE_AUTH_CERTIFICATE = 2,
/** Use TLS certificate for client authentication */
@ -53,19 +60,20 @@ typedef struct sAcseAuthenticationParameter* AcseAuthenticationParameter;
struct sAcseAuthenticationParameter
{
AcseAuthenticationMechanism mechanism;
union
{
struct
{
uint8_t* octetString;
int passwordLength;
} password;
} password; /* for mechanism = ACSE_AUTH_PASSWORD */
struct
{
uint8_t* buf;
int length;
} certificate;
} certificate; /* for mechanism = ACSE_AUTH_CERTIFICATE or ACSE_AUTH_TLS */
} value;
};
@ -115,6 +123,10 @@ struct sIsoConnectionParameters
{
AcseAuthenticationParameter acseAuthParameter;
//#if (CONFIG_MMS_SUPPORT_TLS == 1)
TLSConfiguration tlsConfiguration;
//#endif
const char* hostname;
int tcpPort;
@ -158,6 +170,10 @@ IsoConnectionParameters_create(void);
void
IsoConnectionParameters_destroy(IsoConnectionParameters self);
void
IsoConnectionParameters_setTlsConfiguration(IsoConnectionParameters self, TLSConfiguration tlsConfig);
/**
* \brief set the authentication parameter
*
@ -226,7 +242,7 @@ IsoConnectionParameters_setRemoteAddresses(IsoConnectionParameters self, uint32_
* \param aeQualifier the AP-qualifier
*/
void
IsoConnectionParameters_setLocalApTitle(IsoConnectionParameters self, char* apTitle, int aeQualifier);
IsoConnectionParameters_setLocalApTitle(IsoConnectionParameters self, const char* apTitle, int aeQualifier);
/**
* \brief set local addresses for the lower layers

@ -89,13 +89,13 @@ void
IsoConnection_sendMessage(IsoConnection self, ByteBuffer* message, bool handlerMode);
IsoServer
IsoServer_create(void);
IsoServer_create(TLSConfiguration tlsConfiguration);
void
IsoServer_setTcpPort(IsoServer self, int port);
void
IsoServer_setLocalIpAddress(IsoServer self, char* ipAddress);
IsoServer_setLocalIpAddress(IsoServer self, const char* ipAddress);
IsoServerState
IsoServer_getState(IsoServer self);
@ -113,6 +113,9 @@ IsoServer_getAuthenticator(IsoServer self);
void*
IsoServer_getAuthenticatorParameter(IsoServer self);
TLSConfiguration
IsoServer_getTLSConfiguration(IsoServer self);
void
IsoServer_startListening(IsoServer self);

@ -41,6 +41,8 @@ extern "C" {
#include "iso_connection_parameters.h"
#include "linked_list.h"
#include "tls_api.h"
/**
* Contains MMS layer specific parameters
*/
@ -79,6 +81,16 @@ typedef struct sMmsConnection* MmsConnection;
MmsConnection
MmsConnection_create(void);
/**
* \brief Create a new secure (TLS enabled) MmsConnection instance
*
* \param tlsConfig TLS configuration parameters and certificates
*
* \return the newly created instance.
*/
MmsConnection
MmsConnection_createSecure(TLSConfiguration tlsConfig);
/**
* \brief Callback function to intercept raw MMS messages
*
@ -217,7 +229,7 @@ MmsConnection_destroy(MmsConnection self);
* \param self MmsConnection instance to operate on
* \param mmsError user provided variable to store error code
* \param serverName hostname or IP address of the server to connect
* \param serverPort TCP port number of the server to connect (usually 102)
* \param serverPort TCP port number of the server to connect or -1 to use default port (102 for MMS or 3872 for MMS over TLS)
*
* \return true on success. false if the connection attempt failed.
*/

@ -182,7 +182,7 @@ MmsDevice_destroy(MmsDevice* self);
* \return the new MmsDevice instance
*/
MmsDomain*
MmsDevice_getDomain(MmsDevice* self, char* domainId);
MmsDevice_getDomain(MmsDevice* self, const char* domainId);
/**
* \brief Get the MmsTypeSpecification instance of a MMS named variable of VMD scope

@ -64,7 +64,7 @@ typedef void (*MmsConnectionHandler)(void* parameter,
MmsServerConnection connection, MmsServerEvent event);
MmsServer
MmsServer_create(IsoServer isoServer, MmsDevice* device);
MmsServer_create(MmsDevice* device, TLSConfiguration tlsConfiguration);
void
MmsServer_destroy(MmsServer self);
@ -80,6 +80,12 @@ void
MmsServer_installWriteHandler(MmsServer self, MmsWriteVariableHandler,
void* parameter);
void
MmsServer_setLocalIpAddress(MmsServer self, const char* localIpAddress);
bool
MmsServer_isRunning(MmsServer self);
/**
* A connection handler will be invoked whenever a new client connection is opened or closed
*/
@ -94,7 +100,7 @@ MmsDevice*
MmsServer_getDevice(MmsServer self);
MmsValue*
MmsServer_getValueFromCache(MmsServer self, MmsDomain* domain, char* itemId);
MmsServer_getValueFromCache(MmsServer self, MmsDomain* domain, const char* itemId);
bool
MmsServer_isLocked(MmsServer self);

@ -131,6 +131,18 @@ MmsVariableSpecification_getSize(MmsVariableSpecification* self);
MmsVariableSpecification*
MmsVariableSpecification_getChildSpecificationByIndex(MmsVariableSpecification* self, int index);
/**
* \brief return the MmsVariableSpecification of a structure element with the given name
*
* \param self the MmsVariableSpecification object
* \param name the name of the component (structure element)
* \param index (OUT) if not NULL the index of the structure element will be stored there
*
* \return the type specification of the component or NULL if the component was not found
*/
MmsVariableSpecification*
MmsVariableSpecification_getChildSpecificationByName(MmsVariableSpecification* self, const char* name, int* index);
MmsVariableSpecification*
MmsVariableSpecification_getArrayElementSpecification(MmsVariableSpecification* self);

@ -26,6 +26,7 @@
#include "byte_buffer.h"
#include "buffer_chain.h"
#include "iso_connection_parameters.h"
#include "tls_api.h"
#ifndef ACSE_H_
#define ACSE_H_
@ -57,6 +58,10 @@ typedef struct sAcseConnection
IsoApplicationReference applicationReference;
void* authenticatorParameter;
void* securityToken;
#if (CONFIG_MMS_SUPPORT_TLS == 1)
TLSSocket tlsSocket;
#endif
} AcseConnection;
#define ACSE_RESULT_ACCEPT 0
@ -64,7 +69,7 @@ typedef struct sAcseConnection
#define ACSE_RESULT_REJECT_TRANSIENT 2
void
AcseConnection_init(AcseConnection* self, AcseAuthenticator authenticator, void* parameter);
AcseConnection_init(AcseConnection* self, AcseAuthenticator authenticator, void* parameter, TLSSocket tlsSocket);
void
AcseConnection_destroy(AcseConnection* self);

@ -29,6 +29,7 @@
#include "buffer_chain.h"
#include "hal_socket.h"
#include "iso_connection_parameters.h"
#include "tls_api.h"
typedef struct {
TSelector tSelSrc;
@ -41,7 +42,12 @@ typedef struct {
int remoteRef;
int localRef;
int protocolClass;
Socket socket;
//#if (CONFIG_MMS_SUPPORT_TLS == 1)
TLSSocket tlsSocket;
//#endif
CotpOptions options;
bool isLastDataUnit;
ByteBuffer* payload;

@ -25,6 +25,7 @@
#define ISO_SERVER_PRIVATE_H_
#include "hal_socket.h"
#include "tls_api.h"
IsoConnection
IsoConnection_create(Socket socket, IsoServer isoServer);

@ -1,5 +1,5 @@
/*
* mms_connection.h
* mms_server_connection.h
*
* Copyright 2013 Michael Zillgith
*
@ -39,6 +39,10 @@
#include "linked_list.h"
#include "byte_buffer.h"
#ifdef __cplusplus
extern "C" {
#endif
MmsServerConnection
MmsServerConnection_init(MmsServerConnection connection, MmsServer server, IsoConnection isoCon);
@ -67,7 +71,7 @@ MmsServerConnection_parseMessage(MmsServerConnection connection, ByteBuffer* mes
*/
void
MmsServerConnection_sendInformationReportSingleVariableVMDSpecific(MmsServerConnection self,
char* itemId, MmsValue* value, bool handlerMode);
char* itemId, MmsValue* value, bool handlerMode);
/** \brief send information report for a VMD specific named variable list
@ -104,6 +108,10 @@ MmsServerConnection_getNextRequestInvokeId(MmsServerConnection self);
const char*
MmsServerConnection_getFilesystemBasepath(MmsServerConnection self);
#ifdef __cplusplus
}
#endif
#endif /* MMS_SERVER_CONNECTION_H_ */

@ -36,7 +36,7 @@ void
MmsValueCache_insertValue(MmsValueCache self, char* itemId, MmsValue* value);
MmsValue*
MmsValueCache_lookupValue(MmsValueCache self, char* itemId);
MmsValueCache_lookupValue(MmsValueCache self, const char* itemId);
void
MmsValueCache_destroy(MmsValueCache self);

@ -68,9 +68,10 @@ authenticateClient(AcseConnection* self, AcseAuthenticationMechanism mechanism,
authParameter->value.password.octetString = authValue;
authParameter->value.password.passwordLength = authValueLen;
}
//TODO Check if we are in a TLS connection: if mechanism == ACSE_AUTH_NONE provide client certificate if present
// --> mechanism = ACSE_AUTH_TLS
else if (mechanism == ACSE_AUTH_TLS) {
authParameter->value.certificate.buf = authValue;
authParameter->value.certificate.length = authValueLen;
}
return self->authenticator(self->authenticatorParameter, authParameter, &(self->securityToken), &(self->applicationReference));
}
@ -84,6 +85,26 @@ checkAuthentication(AcseConnection* self, uint8_t* authMechanism, int authMechLe
AcseAuthenticationMechanism mechanism = checkAuthMechanismName(authMechanism, authMechLen);
if (mechanism == ACSE_AUTH_NONE) {
#if (CONFIG_MMS_SUPPORT_TLS == 1)
if (self->tlsSocket) {
int certLen;
uint8_t* certBuf = TLSSocket_getPeerCertificate(self->tlsSocket, &certLen);
if (certBuf) {
mechanism = ACSE_AUTH_TLS;
authValue = certBuf;
authValueLen = certLen;
}
}
#endif /* (CONFIG_MMS_SUPPORT_TLS == 1) */
}
return authenticateClient(self, mechanism, authValue, authValueLen);
}
else
@ -328,14 +349,19 @@ parseAarqPdu(AcseConnection* self, uint8_t* buffer, int bufPos, int maxBufPos)
}
void
AcseConnection_init(AcseConnection* self, AcseAuthenticator authenticator, void* parameter)
AcseConnection_init(AcseConnection* self, AcseAuthenticator authenticator, void* parameter, TLSSocket tlsSocket)
{
self->state = idle;
self->nextReference = 0;
self->userDataBuffer = NULL;
self->userDataBufferSize = 0;
self->authenticator= authenticator;
self->authenticator = authenticator;
self->authenticatorParameter = parameter;
#if (CONFIG_MMS_SUPPORT_TLS == 1)
self->tlsSocket = tlsSocket;
#endif
memset(&(self->applicationReference), 0, sizeof(self->applicationReference));
}

@ -34,6 +34,8 @@
#include "iso_presentation.h"
#include "iso_client_connection.h"
#include "acse.h"
#include "tls_api.h"
#ifndef DEBUG_ISO_CLIENT
#ifdef DEBUG
@ -56,7 +58,13 @@ struct sIsoClientConnection
IsoIndicationCallback callback;
void* callbackParameter;
volatile int state;
Socket socket;
#if (CONFIG_MMS_SUPPORT_TLS == 1)
TLSSocket tlsSocket;
#endif
CotpConnection* cotpConnection;
IsoPresentation* presentation;
IsoSession* session;
@ -159,6 +167,11 @@ connectionHandlingThread(IsoClientConnection self)
self->state = STATE_IDLE;
#if (CONFIG_MMS_SUPPORT_TLS == 1)
if (self->cotpConnection->tlsSocket)
TLSSocket_close(self->cotpConnection->tlsSocket);
#endif
Socket_destroy(self->socket);
if (DEBUG_ISO_CLIENT)
@ -251,6 +264,27 @@ IsoClientConnection_associate(IsoClientConnection self, IsoConnectionParameters
/* COTP (ISO transport) handshake */
CotpConnection_init(self->cotpConnection, self->socket, self->receiveBuffer, self->cotpReadBuffer, self->cotpWriteBuffer);
#if (CONFIG_MMS_SUPPORT_TLS == 1)
if (params->tlsConfiguration) {
/* create TLSSocket and start TLS authentication */
TLSSocket tlsSocket = TLSSocket_create(self->socket, params->tlsConfiguration, false);
if (tlsSocket)
self->cotpConnection->tlsSocket = tlsSocket;
else {
if (DEBUG_ISO_CLIENT)
printf("TLS handshake failed!\n");
goto returnError;
}
}
#endif /* (CONFIG_MMS_SUPPORT_TLS == 1) */
/* COTP (ISO transport) handshake */
CotpIndication cotpIndication =
CotpConnection_sendConnectionRequestMessage(self->cotpConnection, params);
@ -280,7 +314,7 @@ IsoClientConnection_associate(IsoClientConnection self, IsoConnectionParameters
acsePayload->length = payload->size;
acsePayload->nextPart = NULL;
AcseConnection_init(&(self->acseConnection), NULL, NULL);
AcseConnection_init(&(self->acseConnection), NULL, NULL, NULL);
AcseAuthenticationParameter authParameter = params->acseAuthParameter;
@ -383,7 +417,7 @@ returnError:
Socket_destroy(self->socket);
self->socket = NULL;
Semaphore_post(self->transmitBufferMutex); //TODO check
Semaphore_post(self->transmitBufferMutex);
return;
}

@ -78,6 +78,15 @@ IsoConnectionParameters_destroy(IsoConnectionParameters self)
GLOBAL_FREEMEM(self);
}
void
IsoConnectionParameters_setTlsConfiguration(IsoConnectionParameters self, TLSConfiguration tlsConfig)
{
//#if (CONFIG_MMS_SUPPORT_TLS == 1)
self->tlsConfiguration = tlsConfig;
//#endif
}
void
IsoConnectionParameters_setAcseAuthenticationParameter(IsoConnectionParameters self,
AcseAuthenticationParameter acseAuthParameter)
@ -113,7 +122,7 @@ IsoConnectionParameters_setRemoteAddresses(IsoConnectionParameters self, uint32_
void
IsoConnectionParameters_setLocalApTitle(IsoConnectionParameters self, char* apTitle, int aeQualifier)
IsoConnectionParameters_setLocalApTitle(IsoConnectionParameters self, const char* apTitle, int aeQualifier)
{
if (apTitle == NULL)
self->localApTitleLen = 0;

@ -161,6 +161,20 @@ writeDataTpduHeader(CotpConnection* self, int isLastUnit)
self->writeBuffer->size = 7;
}
static inline int
writeToSocket(CotpConnection* self, uint8_t* buf, int size)
{
#if (CONFIG_MMS_SUPPORT_TLS == 1)
if (self->tlsSocket)
return TLSSocket_write(self->tlsSocket, buf, size);
else
return Socket_write(self->socket, buf, size);
#else
return Socket_write(self->socket, buf, size);
#endif
}
static bool
sendBuffer(CotpConnection* self)
{
@ -171,7 +185,7 @@ sendBuffer(CotpConnection* self)
int sentBytes;
do {
sentBytes = Socket_write(self->socket, ByteBuffer_getBuffer(self->writeBuffer), writeBufferPosition);
sentBytes = writeToSocket(self, ByteBuffer_getBuffer(self->writeBuffer), writeBufferPosition);
if (sentBytes == -1)
goto exit_function;
@ -435,6 +449,7 @@ CotpConnection_init(CotpConnection* self, Socket socket,
{
self->state = 0;
self->socket = socket;
self->tlsSocket = NULL;
self->remoteRef = -1;
self->localRef = 1;
self->protocolClass = -1;
@ -634,6 +649,20 @@ CotpConnection_resetPayload(CotpConnection* self)
self->payload->size = 0;
}
static inline int
readFromSocket(CotpConnection* self, uint8_t* buf, int size)
{
#if (CONFIG_MMS_SUPPORT_TLS == 1)
if (self->tlsSocket)
return TLSSocket_read(self->tlsSocket, buf, size);
else
return Socket_read(self->socket, buf, size);
#else
return Socket_read(self->socket, buf, size);
#endif
}
TpktState
CotpConnection_readToTpktBuffer(CotpConnection* self)
{
@ -647,7 +676,7 @@ CotpConnection_readToTpktBuffer(CotpConnection* self)
if (bufPos < 4) {
readBytes = Socket_read(self->socket, buffer + bufPos, 4 - bufPos);
readBytes = readFromSocket(self, buffer + bufPos, 4 - bufPos);
if (readBytes < 0)
goto exit_closed;
@ -680,7 +709,7 @@ CotpConnection_readToTpktBuffer(CotpConnection* self)
goto exit_waiting;
}
readBytes = Socket_read(self->socket, buffer + bufPos, self->packetSize - bufPos);
readBytes = readFromSocket(self, buffer + bufPos, self->packetSize - bufPos);
if (readBytes < 0)
goto exit_closed;

@ -28,6 +28,8 @@
#include "mms_client_internal.h"
#include "stack_config.h"
#include "tls_api.h"
#include <MmsPdu.h>
#include "byte_buffer.h"
@ -1052,6 +1054,25 @@ MmsConnection_create()
return self;
}
MmsConnection
MmsConnection_createSecure(TLSConfiguration tlsConfig)
{
MmsConnection self = MmsConnection_create();
#if (CONFIG_MMS_SUPPORT_TLS == 1)
if (self != NULL) {
IsoConnectionParameters connectionParameters = MmsConnection_getIsoConnectionParameters(self);
TLSConfiguration_setClientMode(tlsConfig);
IsoConnectionParameters_setTlsConfiguration(connectionParameters, tlsConfig);
}
#endif /* (CONFIG_MMS_SUPPORT_TLS == 1) */
return self;
}
void
MmsConnection_destroy(MmsConnection self)
{
@ -1184,6 +1205,13 @@ waitForConnectResponse(MmsConnection self)
bool
MmsConnection_connect(MmsConnection self, MmsError* mmsError, const char* serverName, int serverPort)
{
if (serverPort == -1) {
if (self->isoParameters->tlsConfiguration)
serverPort = 3782;
else
serverPort = 102;
}
IsoConnectionParameters_setTcpParameters(self->isoParameters, serverName, serverPort);
if (self->parameters.maxPduSize == -1)

@ -276,6 +276,27 @@ MmsVariableSpecification_getChildSpecificationByIndex(MmsVariableSpecification*
return self->typeSpec.structure.elements[index];
}
MmsVariableSpecification*
MmsVariableSpecification_getChildSpecificationByName(MmsVariableSpecification* self, const char* name, int* index)
{
if (self->type != MMS_STRUCTURE)
return NULL;
int i;
for (i = 0; i < self->typeSpec.structure.elementCount; i++) {
if (!strcmp(self->typeSpec.structure.elements[i]->name, name)) {
if (index != NULL)
*index = i;
return self->typeSpec.structure.elements[i];
}
}
return NULL;
}
MmsVariableSpecification*
MmsVariableSpecification_getArrayElementSpecification(MmsVariableSpecification* self)
{

@ -63,7 +63,7 @@ MmsDevice_destroy(MmsDevice* self)
}
MmsDomain*
MmsDevice_getDomain(MmsDevice* self, char* domainId)
MmsDevice_getDomain(MmsDevice* self, const char* domainId)
{
int i;

@ -48,11 +48,11 @@ createValueCaches(MmsDevice* device)
}
MmsServer
MmsServer_create(IsoServer isoServer, MmsDevice* device)
MmsServer_create(MmsDevice* device, TLSConfiguration tlsConfiguration)
{
MmsServer self = (MmsServer) GLOBAL_CALLOC(1, sizeof(struct sMmsServer));
self->isoServer = isoServer;
self->isoServer = IsoServer_create(tlsConfiguration);
self->device = device;
self->openConnections = Map_create();
self->valueCaches = createValueCaches(device);
@ -64,12 +64,26 @@ MmsServer_create(IsoServer isoServer, MmsDevice* device)
self->modelMutex = Semaphore_create(1);
self->transmitBufferMutex = Semaphore_create(1);
IsoServer_setUserLock(isoServer, self->modelMutex);
IsoServer_setUserLock(self->isoServer, self->modelMutex);
#endif
return self;
}
void
MmsServer_setLocalIpAddress(MmsServer self, const char* localIpAddress)
{
IsoServer_setLocalIpAddress(self->isoServer, localIpAddress);
}
bool
MmsServer_isRunning(MmsServer self)
{
if (IsoServer_getState(self->isoServer) == ISO_SVR_STATE_RUNNING)
return true;
else
return false;
}
void
MmsServer_setFilestoreBasepath(MmsServer self, const char* basepath)
@ -225,6 +239,8 @@ deleteSingleCache(MmsValueCache cache)
void
MmsServer_destroy(MmsServer self)
{
IsoServer_destroy(self->isoServer);
Map_deleteDeep(self->openConnections, false, closeConnection);
Map_deleteDeep(self->valueCaches, false, (void (*) (void*)) deleteSingleCache);
@ -244,7 +260,7 @@ MmsServer_destroy(MmsServer self)
}
MmsValue*
MmsServer_getValueFromCache(MmsServer self, MmsDomain* domain, char* itemId)
MmsServer_getValueFromCache(MmsServer self, MmsDomain* domain, const char* itemId)
{
MmsValueCache cache = (MmsValueCache) Map_getEntry(self->valueCaches, domain);
@ -360,7 +376,10 @@ void
MmsServer_startListening(MmsServer server, int tcpPort)
{
IsoServer_setConnectionHandler(server->isoServer, isoConnectionIndicationHandler, (void*) server);
IsoServer_setTcpPort(server->isoServer, tcpPort);
if (tcpPort != -1)
IsoServer_setTcpPort(server->isoServer, tcpPort);
IsoServer_startListening(server->isoServer);
}

@ -82,19 +82,19 @@ getParentSubString(char* itemId)
return NULL;
}
static char*
getChildSubString (char* itemId, char* parentId)
static const char*
getChildSubString (const char* itemId, char* parentId)
{
return itemId + strlen(parentId) + 1;
}
static MmsValue*
searchCacheForValue(MmsValueCache self, char* itemId, char* parentId)
searchCacheForValue(MmsValueCache self, const char* itemId, char* parentId)
{
MmsValueCacheEntry* cacheEntry;
MmsValue* value = NULL;
cacheEntry = (MmsValueCacheEntry*) Map_getEntry(self->map, parentId);
cacheEntry = (MmsValueCacheEntry*) Map_getEntry(self->map, (void*) parentId);
if (cacheEntry == NULL) {
char* parentItemId = getParentSubString(parentId);
@ -105,7 +105,7 @@ searchCacheForValue(MmsValueCache self, char* itemId, char* parentId)
}
else {
char* childId = getChildSubString(itemId, parentId);
const char* childId = getChildSubString(itemId, parentId);
MmsVariableSpecification* typeSpec = MmsDomain_getNamedVariable(self->domain, parentId);
value = MmsVariableSpecification_getChildValue(typeSpec, cacheEntry->value, childId);
@ -115,7 +115,7 @@ searchCacheForValue(MmsValueCache self, char* itemId, char* parentId)
}
MmsValue*
MmsValueCache_lookupValue(MmsValueCache self, char* itemId)
MmsValueCache_lookupValue(MmsValueCache self, const char* itemId)
{
// get value for first matching key substring!
// Then iterate the value for the exact value.
@ -124,7 +124,7 @@ MmsValueCache_lookupValue(MmsValueCache self, char* itemId)
MmsValueCacheEntry* cacheEntry;
cacheEntry = (MmsValueCacheEntry*) Map_getEntry(self->map, itemId);
cacheEntry = (MmsValueCacheEntry*) Map_getEntry(self->map, (void*) itemId);
if (cacheEntry == NULL) {
char* itemIdCopy = StringUtils_copyString(itemId);

@ -69,6 +69,11 @@ struct sIsoConnection
IsoServer isoServer;
Socket socket;
#if (CONFIG_MMS_SUPPORT_TLS == 1)
TLSSocket tlsSocket;
#endif
int state;
IsoSession* session;
IsoPresentation* presentation;
@ -445,6 +450,23 @@ IsoConnection_create(Socket socket, IsoServer isoServer)
{
IsoConnection self = (IsoConnection) GLOBAL_CALLOC(1, sizeof(struct sIsoConnection));
self->socket = socket;
#if (CONFIG_MMS_SUPPORT_TLS == 1)
if (IsoServer_getTLSConfiguration(isoServer) != NULL) {
self->tlsSocket = TLSSocket_create(socket, IsoServer_getTLSConfiguration(isoServer), true);
if (self->tlsSocket == NULL) {
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: IsoConnection - TLS initialization failed\n");
GLOBAL_FREEMEM(self);
return NULL;
}
}
#endif /* (CONFIG_MMS_SUPPORT_TLS == 1) */
self->receiveBuffer = (uint8_t*) GLOBAL_MALLOC(RECEIVE_BUF_SIZE);
self->sendBuffer = (uint8_t*) GLOBAL_MALLOC(SEND_BUF_SIZE);
self->msgRcvdHandler = NULL;
@ -469,6 +491,11 @@ IsoConnection_create(Socket socket, IsoServer isoServer)
self->cotpConnection = (CotpConnection*) GLOBAL_CALLOC(1, sizeof(CotpConnection));
CotpConnection_init(self->cotpConnection, self->socket, &(self->rcvBuffer), &(self->cotpReadBuffer), &(self->cotpWriteBuffer));
#if (CONFIG_MMS_SUPPORT_TLS == 1)
if (self->tlsSocket)
self->cotpConnection->tlsSocket = self->tlsSocket;
#endif /* (CONFIG_MMS_SUPPORT_TLS == 1) */
self->session = (IsoSession*) GLOBAL_CALLOC(1, sizeof(IsoSession));
IsoSession_init(self->session);
@ -476,8 +503,14 @@ IsoConnection_create(Socket socket, IsoServer isoServer)
IsoPresentation_init(self->presentation);
self->acseConnection = (AcseConnection*) GLOBAL_CALLOC(1, sizeof(AcseConnection));
#if (CONFIG_MMS_SUPPORT_TLS == 1)
AcseConnection_init(self->acseConnection, IsoServer_getAuthenticator(self->isoServer),
IsoServer_getAuthenticatorParameter(self->isoServer));
IsoServer_getAuthenticatorParameter(self->isoServer), self->tlsSocket);
#else
AcseConnection_init(self->acseConnection, IsoServer_getAuthenticator(self->isoServer),
IsoServer_getAuthenticatorParameter(self->isoServer), NULL);
#endif
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: IsoConnection: Start to handle connection for client %s\n", self->clientAddress);
@ -572,6 +605,11 @@ IsoConnection_close(IsoConnection self)
self->state = ISO_CON_STATE_STOPPED;
self->socket = NULL;
#if (CONFIG_MMS_SUPPORT_TLS == 1)
if (self->tlsSocket)
TLSSocket_close(self->tlsSocket);
#endif
Socket_destroy(socket);
}
}

@ -63,7 +63,9 @@ struct sIsoServer {
Socket serverSocket;
int tcpPort;
char* localIpAddress;
const char* localIpAddress;
TLSConfiguration tlsConfiguration;
#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1)
LinkedList openClientConnections;
@ -349,10 +351,14 @@ handleIsoConnections(IsoServer self)
IsoConnection isoConnection = IsoConnection_create(connectionSocket, self);
addClientConnection(self, isoConnection);
if (isoConnection) {
self->connectionHandler(ISO_CONNECTION_OPENED, self->connectionHandlerParameter,
isoConnection);
addClientConnection(self, isoConnection);
self->connectionHandler(ISO_CONNECTION_OPENED, self->connectionHandlerParameter,
isoConnection);
}
}
@ -385,11 +391,14 @@ handleIsoConnectionsThreadless(IsoServer self)
IsoConnection isoConnection = IsoConnection_create(connectionSocket, self);
addClientConnection(self, isoConnection);
if (isoConnection) {
self->connectionHandler(ISO_CONNECTION_OPENED, self->connectionHandlerParameter,
isoConnection);
addClientConnection(self, isoConnection);
self->connectionHandler(ISO_CONNECTION_OPENED, self->connectionHandlerParameter,
isoConnection);
}
}
handleClientConnections(self);
@ -431,12 +440,18 @@ isoServerThread(void* isoServerParam)
#endif
IsoServer
IsoServer_create()
IsoServer_create(TLSConfiguration tlsConfiguration)
{
IsoServer self = (IsoServer) GLOBAL_CALLOC(1, sizeof(struct sIsoServer));
self->state = ISO_SVR_STATE_IDLE;
self->tcpPort = TCP_PORT;
if (tlsConfiguration == NULL)
self->tcpPort = TCP_PORT;
else
self->tcpPort = SECURE_TCP_PORT;
self->tlsConfiguration = tlsConfiguration;
#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1)
self->openClientConnections = LinkedList_create();
@ -462,7 +477,7 @@ IsoServer_setTcpPort(IsoServer self, int port)
}
void
IsoServer_setLocalIpAddress(IsoServer self, char* ipAddress)
IsoServer_setLocalIpAddress(IsoServer self, const char* ipAddress)
{
self->localIpAddress = ipAddress;
}
@ -492,6 +507,12 @@ IsoServer_getAuthenticatorParameter(IsoServer self)
return self->authenticatorParameter;
}
TLSConfiguration
IsoServer_getTLSConfiguration(IsoServer self)
{
return self->tlsConfiguration;
}
#if (CONFIG_MMS_THREADLESS_STACK != 1)
void
IsoServer_startListening(IsoServer self)

@ -0,0 +1,59 @@
#ifndef MBEDTLS_CONFIG_H
#define MBEDTLS_CONFIG_H
/* System support */
#define MBEDTLS_HAVE_ASM
#define MBEDTLS_HAVE_TIME
#define MBEDTLS_NO_UDBL_DIVISION
#define MBEDTLS_PLATFORM_C
#define MBEDTLS_DEBUG_C
/* mbed TLS feature support */
#define MBEDTLS_CIPHER_MODE_CBC
#define MBEDTLS_PKCS1_V15
#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
#define MBEDTLS_SSL_PROTO_TLS1_1
#define MBEDTLS_SSL_PROTO_TLS1
#define MBEDTLS_SSL_RENEGOTIATION
#define MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES
/* mbed TLS modules */
#define MBEDTLS_AES_C
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_ASN1_WRITE_C
#define MBEDTLS_BIGNUM_C
#define MBEDTLS_CIPHER_C
#define MBEDTLS_CTR_DRBG_C
//#define MBEDTLS_DES_C
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_MD_C
#define MBEDTLS_MD5_C
#define MBEDTLS_NET_C
#define MBEDTLS_OID_C
#define MBEDTLS_PK_C
#define MBEDTLS_PK_PARSE_C
#define MBEDTLS_RSA_C
#define MBEDTLS_SHA1_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_SSL_CLI_C
#define MBEDTLS_SSL_SRV_C
#define MBEDTLS_SSL_TLS_C
#define MBEDTLS_X509_CRT_PARSE_C
#define MBEDTLS_X509_USE_C
#define MBEDTLS_SSL_CACHE_C
/* For test certificates */
#define MBEDTLS_BASE64_C
#define MBEDTLS_CERTS_C
#define MBEDTLS_PEM_PARSE_C
#define MBEDTLS_PKCS12_C
#define MBEDTLS_PKCS5_C
/* For testing with compat.sh */
#define MBEDTLS_FS_IO
#include "mbedtls/check_config.h"
#endif /* MBEDTLS_CONFIG_H */

@ -0,0 +1,497 @@
/*
* tls_mbedtls.c
*
* TLS API for TCP/IP protocol stacks
*
* Copyright 2017 MZ Automation GmbH
*
* Implementation of the TLS abstraction layer for mbedtls
*
*/
#include <string.h>
#include "tls_api.h"
#include "hal_thread.h"
#include "lib_memory.h"
#include "linked_list.h"
//#include "mbedtls/config.h"
#include "mbedtls/platform.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/certs.h"
#include "mbedtls/x509.h"
#include "mbedtls/ssl.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/error.h"
#include "mbedtls/debug.h"
#define CONFIG_DEBUG_TLS 0
#if (CONFIG_DEBUG_TLS == 1)
#define DEBUG_PRINT(appId, fmt, ...) fprintf(stderr, "%s: " fmt, appId, ## __VA_ARGS__)
#else
#define DEBUG_PRINT(fmt, ...) {do {} while(0);}
#endif
struct sTLSConfiguration {
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_x509_crt ownCertificate;
mbedtls_pk_context ownKey;
mbedtls_x509_crt cacerts;
mbedtls_ssl_config conf;
LinkedList /* <mbedtls_x509_crt*> */ allowedCertificates;
bool chainValidation;
bool allowOnlyKnownCertificates;
};
struct sTLSSocket {
mbedtls_ssl_context ssl;
Socket socket;
mbedtls_ssl_config conf;
TLSConfiguration tlsConfig;
bool storePeerCert;
uint8_t* peerCert;
int peerCertLength;
};
static bool
compareCertificates(mbedtls_x509_crt *crt1, mbedtls_x509_crt *crt2)
{
if (crt1 != NULL && crt2 != NULL) {
if (crt1->sig.len == crt2->sig.len) {
if (memcmp(crt1->sig.p, crt2->sig.p, crt1->sig.len) == 0)
return true;
}
}
return false;
}
static int
verifyCertificate (void* parameter, mbedtls_x509_crt *crt, int certificate_depth, uint32_t *flags)
{
TLSSocket self = (TLSSocket) parameter;
DEBUG_PRINT("TLS", "Verify cert: depth %i\n", certificate_depth);
DEBUG_PRINT("TLS", " flags: %08x\n", *flags);
char buffer[1024];
mbedtls_x509_crt_info(buffer, 1023, " ", crt);
DEBUG_PRINT("TLS", "%s\n", buffer);
if (self->tlsConfig->chainValidation == false) {
if (certificate_depth != 0)
*flags = 0;
}
if (certificate_depth == 0) {
if (self->tlsConfig->allowOnlyKnownCertificates) {
DEBUG_PRINT("TLS", "Check against list of allowed certs\n");
bool certMatches = false;
LinkedList certList = LinkedList_getNext(self->tlsConfig->allowedCertificates);
while (certList) {
mbedtls_x509_crt* allowedCert = (mbedtls_x509_crt*) LinkedList_getData(certList);
DEBUG_PRINT("TLS", "Compare With:\n");
mbedtls_x509_crt_info(buffer, 1023, " ", allowedCert);
DEBUG_PRINT("TLS", "%s\n", buffer);
if (compareCertificates(allowedCert, crt)) {
certMatches = true;
break;
}
certList = LinkedList_getNext(certList);
}
if (certMatches)
*flags = 0;
else
return 1;
}
if (self->storePeerCert) {
if (*flags == 0) {
self->peerCertLength = crt->raw.len;
self->peerCert = (uint8_t*) GLOBAL_MALLOC(self->peerCertLength);
memcpy(self->peerCert, crt->raw.p, self->peerCertLength);
}
}
}
return 0;
}
TLSConfiguration
TLSConfiguration_create()
{
TLSConfiguration self = (TLSConfiguration) GLOBAL_MALLOC(sizeof(struct sTLSConfiguration));
if (self != NULL) {
mbedtls_ssl_config_init( &(self->conf) );
mbedtls_x509_crt_init( &(self->ownCertificate) );
mbedtls_x509_crt_init( &(self->cacerts));
mbedtls_pk_init( &(self->ownKey) );
mbedtls_entropy_init( &(self->entropy) );
mbedtls_ctr_drbg_init( &(self->ctr_drbg) );
//WARINING is fixed to server!
mbedtls_ssl_config_defaults( &(self->conf),
MBEDTLS_SSL_IS_SERVER,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT );
mbedtls_ctr_drbg_seed( &(self->ctr_drbg), mbedtls_entropy_func, &(self->entropy), NULL, 0);
mbedtls_ssl_conf_rng( &(self->conf), mbedtls_ctr_drbg_random, &(self->ctr_drbg) );
mbedtls_ssl_conf_authmode(&(self->conf), MBEDTLS_SSL_VERIFY_REQUIRED);
mbedtls_ssl_conf_renegotiation(&(self->conf), MBEDTLS_SSL_RENEGOTIATION_ENABLED);
//static int hashes[] = {3,4,5,6,7,8,0};
// mbedtls_ssl_conf_sig_hashes(&(self->conf), hashes);
self->allowedCertificates = LinkedList_create();
/* default behavior is to allow all certificates that are signed by the CA */
self->chainValidation = true;
self->allowOnlyKnownCertificates = false;
}
return self;
}
void
TLSConfiguration_setClientMode(TLSConfiguration self)
{
self->conf.endpoint = MBEDTLS_SSL_IS_CLIENT;
}
void
TLSConfiguration_setChainValidation(TLSConfiguration self, bool value)
{
self->chainValidation = value;
}
void
TLSConfiguration_setAllowOnlyKnownCertificates(TLSConfiguration self, bool value)
{
self->allowOnlyKnownCertificates = value;
}
bool
TLSConfiguration_setOwnCertificate(TLSConfiguration self, uint8_t* certificate, int certLen)
{
int ret = mbedtls_x509_crt_parse(&(self->ownCertificate), certificate, certLen);
if (ret != 0)
printf("mbedtls_x509_crt_parse returned %d\n", ret);
return (ret == 0);
}
bool
TLSConfiguration_setOwnCertificateFromFile(TLSConfiguration self, const char* filename)
{
int ret = mbedtls_x509_crt_parse_file(&(self->ownCertificate), filename);
if (ret != 0)
DEBUG_PRINT("TLS", "mbedtls_x509_crt_parse_file returned %d\n", ret);
return (ret == 0);
}
bool
TLSConfiguration_setOwnKey(TLSConfiguration self, uint8_t* key, int keyLen, const char* keyPassword)
{
int ret = mbedtls_pk_parse_key(&(self->ownKey), key, keyLen, (const uint8_t*) keyPassword, (keyPassword == NULL) ? 0 : strlen(keyPassword));
if (ret != 0)
DEBUG_PRINT("TLS", "mbedtls_pk_parse_key returned %d\n", ret);
return (ret == 0);
}
bool
TLSConfiguration_setOwnKeyFromFile(TLSConfiguration self, const char* filename, const char* keyPassword)
{
int ret = mbedtls_pk_parse_keyfile(&(self->ownKey), filename, keyPassword);
if (ret != 0)
DEBUG_PRINT("TLS", "mbedtls_pk_parse_keyfile returned %d\n", ret);
return (ret == 0);
}
bool
TLSConfiguration_addAllowedCertificate(TLSConfiguration self, uint8_t* certificate, int certLen)
{
mbedtls_x509_crt* cert = (mbedtls_x509_crt*) GLOBAL_CALLOC(1, sizeof(mbedtls_x509_crt));
int ret = mbedtls_x509_crt_parse(cert, certificate, certLen);
if (ret == 0) {
LinkedList_add(self->allowedCertificates, cert);
return true;
}
else {
GLOBAL_FREEMEM(cert);
return false;
}
}
bool
TLSConfiguration_addAllowedCertificateFromFile(TLSConfiguration self, const char* filename)
{
mbedtls_x509_crt* cert = (mbedtls_x509_crt*) GLOBAL_CALLOC(1, sizeof(mbedtls_x509_crt));
int ret = mbedtls_x509_crt_parse_file(cert, filename);
if (ret == 0) {
LinkedList_add(self->allowedCertificates, cert);
return true;
}
else {
GLOBAL_FREEMEM(cert);
return false;
}
}
bool
TLSConfiguration_addCACertificate(TLSConfiguration self, uint8_t* certificate, int certLen)
{
int ret = mbedtls_x509_crt_parse(&(self->cacerts), certificate, certLen);
if (ret != 0) {
DEBUG_PRINT("TLS", "mbedtls_x509_crt_parse returned %d\n", ret);
return false;
}
return (ret == 0);
}
bool
TLSConfiguration_addCACertificateFromFile(TLSConfiguration self, const char* filename)
{
int ret = mbedtls_x509_crt_parse_file(&(self->cacerts), filename);
if (ret != 0)
DEBUG_PRINT("TLS", "mbedtls_x509_crt_parse returned %d\n", ret);
return (ret == 0);
}
void
TLSConfiguration_destroy(TLSConfiguration self)
{
mbedtls_x509_crt_free(&(self->ownCertificate));
mbedtls_x509_crt_free(&(self->cacerts));
mbedtls_pk_free(&(self->ownKey));
mbedtls_ssl_config_free(&(self->conf));
LinkedList certElem = LinkedList_getNext(self->allowedCertificates);
while (certElem) {
mbedtls_x509_crt* cert = (mbedtls_x509_crt*) LinkedList_getData(certElem);
mbedtls_x509_crt_free(cert);
certElem = LinkedList_getNext(certElem);
}
LinkedList_destroy(self->allowedCertificates);
GLOBAL_FREEMEM(self);
}
static int
readFunction(void* ctx, unsigned char* buf, size_t len)
{
int ret = Socket_read((Socket) ctx, buf, len);
if ((ret == 0) && (len > 0))
return MBEDTLS_ERR_SSL_WANT_READ;
return ret;
}
TLSSocket
TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClientCert)
{
TLSSocket self = (TLSSocket) GLOBAL_CALLOC(1, sizeof(struct sTLSSocket));
if (self != NULL) {
self->socket = socket;
self->tlsConfig = configuration;
self->storePeerCert = storeClientCert;
self->peerCert = NULL;
self->peerCertLength = 0;
memcpy(&(self->conf), &(configuration->conf), sizeof(mbedtls_ssl_config));
mbedtls_ssl_conf_verify(&(self->conf), verifyCertificate, (void*) self);
int ret;
mbedtls_ssl_conf_ca_chain( &(self->conf), &(configuration->cacerts), NULL );
ret = mbedtls_ssl_conf_own_cert( &(self->conf), &(configuration->ownCertificate), &(configuration->ownKey));
if (ret != 0)
DEBUG_PRINT("TLS", "mbedtls_ssl_conf_own_cert returned %d\n", ret);
ret = mbedtls_ssl_setup( &(self->ssl), &(self->conf) );
if (ret != 0)
DEBUG_PRINT("TLS", "mbedtls_ssl_setup returned %d\n", ret);
mbedtls_ssl_set_bio(&(self->ssl), socket, (mbedtls_ssl_send_t*) Socket_write,
(mbedtls_ssl_recv_t*) readFunction, NULL);
while( (ret = mbedtls_ssl_handshake(&(self->ssl)) ) != 0 )
{
if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE )
{
DEBUG_PRINT("TLS", "mbedtls_ssl_handshake returned %d\n\n", ret );
GLOBAL_FREEMEM(self);
return NULL;
}
}
}
return self;
}
uint8_t*
TLSSocket_getPeerCertificate(TLSSocket self, int* certSize)
{
if (certSize)
*certSize = self->peerCertLength;
return self->peerCert;
}
int
TLSSocket_read(TLSSocket self, uint8_t* buf, int size)
{
int ret;
int len = size;
do
{
ret = mbedtls_ssl_read( &(self->ssl), buf, len );
if( ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE )
continue;
if( ret <= 0 )
{
switch( ret )
{
case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
DEBUG_PRINT("TLS", " connection was closed gracefully\n" );
len = -1;
break;
case MBEDTLS_ERR_NET_CONN_RESET:
len = -1;
DEBUG_PRINT("TLS", " connection was reset by peer\n" );
break;
default:
DEBUG_PRINT("TLS", " mbedtls_ssl_read returned -0x%x\n", -ret );
len = -1; //TODO is this the correct return value?
break;
}
break;
}
len = ret;
if( ret > 0 )
break;
}
while( 1 );
return len;
}
int
TLSSocket_write(TLSSocket self, uint8_t* buf, int size)
{
int ret;
int len = size;
while( ( ret = mbedtls_ssl_write( &(self->ssl), buf, len ) ) <= 0 )
{
if( ret == MBEDTLS_ERR_NET_CONN_RESET )
{
DEBUG_PRINT("TLS", "peer closed the connection\n" );
return -1;
}
if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE )
{
DEBUG_PRINT("TLS", "mbedtls_ssl_write returned %d\n", ret );
return -1;
}
}
len = ret;
return len;
}
void
TLSSocket_close(TLSSocket self)
{
int ret;
//TODO add timeout?
while( ( ret = mbedtls_ssl_close_notify( &(self->ssl) ) ) < 0 )
{
if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
ret != MBEDTLS_ERR_SSL_WANT_WRITE )
{
DEBUG_PRINT("TLS", "mbedtls_ssl_close_notify returned %d\n", ret );
break;
}
}
Thread_sleep(10);
mbedtls_ssl_config_free(&(self->conf));
mbedtls_ssl_free(&(self->ssl));
GLOBAL_FREEMEM(self);
}

@ -0,0 +1,115 @@
/*
* tls_api.h
*
* TLS API for TCP/IP protocol stacks
*
* Copyright 2017 MZ Automation GmbH
*
* Abstraction layer for different TLS implementations
*
* Implementation connects the TLS API layer with the socket API layer
* and performs all TLS tasks like handshake, encryption/decryption.
*
*/
#ifndef SRC_TLS_TLS_API_H_
#define SRC_TLS_TLS_API_H_
#include "hal_socket.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct sTLSConfiguration* TLSConfiguration;
typedef struct sTLSSocket* TLSSocket;
TLSConfiguration
TLSConfiguration_create(void);
/* will be called by stack automatically */
void
TLSConfiguration_setClientMode(TLSConfiguration self);
void
TLSConfiguration_setChainValidation(TLSConfiguration self, bool value);
void
TLSConfiguration_setAllowOnlyKnownCertificates(TLSConfiguration self, bool value);
bool
TLSConfiguration_setOwnCertificate(TLSConfiguration self, uint8_t* certificate, int certLen);
bool
TLSConfiguration_setOwnCertificateFromFile(TLSConfiguration self, const char* filename);
bool
TLSConfiguration_setOwnKey(TLSConfiguration self, uint8_t* key, int keyLen, const char* keyPassword);
bool
TLSConfiguration_setOwnKeyFromFile(TLSConfiguration self, const char* filename, const char* keyPassword);
bool
TLSConfiguration_addAllowedCertificate(TLSConfiguration self, uint8_t* certifcate, int certLen);
bool
TLSConfiguration_addAllowedCertificateFromFile(TLSConfiguration self, const char* filename);
bool
TLSConfiguration_addCACertificate(TLSConfiguration self, uint8_t* certifcate, int certLen);
bool
TLSConfiguration_addCACertificateFromFile(TLSConfiguration self, const char* filename);
void
TLSConfiguration_destroy(TLSConfiguration self);
TLSSocket
TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClientCert);
bool
TLSSocket_performHandshake(TLSSocket self);
uint8_t*
TLSSocket_getPeerCertificate(TLSSocket self, int* certSize);
/**
* \brief read from socket to local buffer (non-blocking)
*
* The function shall return immediately if no data is available. In this case
* the function returns 0. If an error happens the function shall return -1.
*
* Implementation of this function is MANDATORY
*
* NOTE: The behaviour of this function changed with version 0.8!
*
* \param self the client, connection or server socket instance
* \param buf the buffer where the read bytes are copied to
* \param size the maximum number of bytes to read (size of the provided buffer)
*
* \return the number of bytes read or -1 if an error occurred
*/
int
TLSSocket_read(TLSSocket self, uint8_t* buf, int size);
/**
* \brief send a message through the socket
*
* Implementation of this function is MANDATORY
*
* \param self client, connection or server socket instance
*
* \return number of bytes transmitted of -1 in case of an error
*/
int
TLSSocket_write(TLSSocket self, uint8_t* buf, int size);
void
TLSSocket_close(TLSSocket self);
#ifdef __cplusplus
}
#endif
#endif /* SRC_TLS_TLS_API_H_ */

@ -163,7 +163,6 @@ EXPORTS
IedServer_getAttributeValue @416
IedServer_getDataModel @417
IedServer_getFunctionalConstrainedData @418
IedServer_getIsoServer @419
IedServer_getMmsServer @420
IedServer_handleWriteAccess @421
IedServer_isRunning @422
@ -573,3 +572,6 @@ EXPORTS
IedConnection_writeDataSetValues
MmsVariableSpecification_isValueOfType
IedServer_udpateDbposValue
MmsServer_setLocalIpAddress
MmsServer_isRunning
IedServer_createWithTlsSupport

@ -187,7 +187,6 @@ EXPORTS
IedServer_getAttributeValue @416
IedServer_getDataModel @417
IedServer_getFunctionalConstrainedData @418
IedServer_getIsoServer @419
IedServer_getMmsServer @420
IedServer_handleWriteAccess @421
IedServer_isRunning @422
@ -654,3 +653,6 @@ EXPORTS
IedConnection_writeDataSetValues
MmsVariableSpecification_isValueOfType
IedServer_udpateDbposValue
MmsServer_setLocalIpAddress
MmsServer_isRunning
IedServer_createWithTlsSupport

@ -0,0 +1,6 @@
README
------
For TLS support with mbedtls download the source tarball of version 2.6.0 and extract here in the subfolder
mbedtls-2.6.0
Loading…
Cancel
Save