#ifndef UA_SECURECHANNEL_H_
#define UA_SECURECHANNEL_H_
struct UA_SecureChannel;
typedef struct UA_SecureChannel UA_SecureChannel;
#include <open62541/util.h>
#include <open62541/types.h>
#include <open62541/plugin/log.h>
#include <open62541/plugin/securitypolicy.h>
#include <open62541/plugin/eventloop.h>
#include <open62541/transport_generated.h>
#include "open62541_queue.h"
#include "util/ua_util_internal.h"
_UA_BEGIN_DECLS
static UA_INLINE UA_Boolean
UA_SecurityPolicy_isEcc(const UA_SecurityPolicy *policy) {
return policy != NULL &&
(policy->policyType == UA_SECURITYPOLICYTYPE_ECC ||
policy->policyType == UA_SECURITYPOLICYTYPE_ECC_AEAD);
}
static UA_INLINE UA_Boolean
UA_SecurityPolicy_isAead(const UA_SecurityPolicy *policy) {
return policy != NULL && policy->policyType == UA_SECURITYPOLICYTYPE_ECC_AEAD;
}
struct UA_Session;
typedef struct UA_Session UA_Session;
#define UA_SECURECHANNEL_MESSAGEHEADER_LENGTH 8
#define UA_SECURECHANNEL_CHANNELHEADER_LENGTH 12
#define UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH 4
#define UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH 8
#define UA_SECURECHANNEL_SYMMETRIC_HEADER_UNENCRYPTEDLENGTH \
(UA_SECURECHANNEL_CHANNELHEADER_LENGTH + \
UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH)
#define UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH \
(UA_SECURECHANNEL_CHANNELHEADER_LENGTH + \
UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH + \
UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH)
#define UA_SECURECHANNEL_MESSAGE_MIN_LENGTH 16
typedef struct UA_Chunk {
TAILQ_ENTRY(UA_Chunk) pointers;
UA_ByteString bytes;
UA_MessageType messageType;
UA_ChunkType chunkType;
UA_UInt32 requestId;
UA_Boolean copied;
} UA_Chunk;
typedef TAILQ_HEAD(UA_ChunkQueue, UA_Chunk) UA_ChunkQueue;
typedef enum {
UA_SECURECHANNELRENEWSTATE_NORMAL,
UA_SECURECHANNELRENEWSTATE_SENT,
UA_SECURECHANNELRENEWSTATE_NEWTOKEN_SERVER,
UA_SECURECHANNELRENEWSTATE_NEWTOKEN_CLIENT
} UA_SecureChannelRenewState;
struct UA_SecureChannel {
UA_SecureChannelState state;
UA_SecureChannelRenewState renewState;
UA_MessageSecurityMode securityMode;
UA_ShutdownReason shutdownReason;
UA_ConnectionConfig config;
UA_String endpointUrl;
UA_String remoteAddress;
UA_ConnectionManager *connectionManager;
uintptr_t connectionId;
UA_NamespaceMapping *namespaceMapping;
TAILQ_ENTRY(UA_SecureChannel) serverEntry;
TAILQ_ENTRY(UA_SecureChannel) componentEntry;
UA_ChannelSecurityToken securityToken;
UA_ChannelSecurityToken altSecurityToken;
UA_SecurityPolicy *securityPolicy;
void *channelContext;
UA_Boolean enhancedSecurity;
UA_Boolean legacySequenceNumbers;
UA_ByteString firstRequestSignature;
UA_ByteString currentIKM;
UA_ByteString channelThumbprint;
UA_ByteString remoteCertificate;
UA_Byte remoteCertificateThumbprint[20];
UA_ByteString remoteNonce;
UA_ByteString localNonce;
UA_UInt32 receiveSequenceNumber;
UA_UInt32 sendSequenceNumber;
UA_Session *sessions;
UA_ChunkQueue chunks;
size_t chunksCount;
size_t chunksLength;
UA_ByteString unprocessed;
size_t unprocessedOffset;
UA_Boolean unprocessedCopied;
UA_DelayedCallback unprocessedDelayed;
void *processOPNHeaderApplication;
UA_StatusCode (*processOPNHeader)(void *application, UA_SecureChannel *channel,
const UA_AsymmetricAlgorithmSecurityHeader *asymHeader);
};
void UA_SecureChannel_init(UA_SecureChannel *channel);
void UA_SecureChannel_shutdown(UA_SecureChannel *channel,
UA_ShutdownReason shutdownReason);
void UA_SecureChannel_clear(UA_SecureChannel *channel);
UA_StatusCode
UA_SecureChannel_processHELACK(UA_SecureChannel *channel,
const UA_TcpAcknowledgeMessage *remoteConfig);
UA_StatusCode
UA_SecureChannel_setSecurityPolicy(UA_SecureChannel *channel,
UA_SecurityPolicy *securityPolicy,
const UA_ByteString *remoteCertificate);
UA_StatusCode
UA_SecureChannel_setSecurityMode(UA_SecureChannel *channel,
UA_MessageSecurityMode securityMode);
UA_Boolean
UA_SecureChannel_isConnected(UA_SecureChannel *channel);
UA_Boolean
UA_SecureChannel_checkTimeout(UA_SecureChannel *channel,
UA_DateTime nowMonotonic);
void
UA_SecureChannel_deleteBuffered(UA_SecureChannel *channel);
UA_StatusCode
UA_SecureChannel_generateLocalNonce(UA_SecureChannel *channel);
UA_StatusCode
UA_SecureChannel_generateLocalKeys(UA_SecureChannel *channel);
UA_StatusCode
generateRemoteKeys(UA_SecureChannel *channel);
UA_StatusCode
UA_SecureChannel_buildCreateSessionSignatureData(
const UA_SecureChannel *channel, const UA_ByteString *clientNonce,
const UA_ByteString *serverNonce, const UA_ByteString *serverChannelCert,
const UA_ByteString *clientChannelCert, UA_ByteString *out);
UA_StatusCode
UA_SecureChannel_buildActivateSessionSignatureData(
const UA_SecureChannel *channel, const UA_ByteString *serverNonce,
const UA_ByteString *clientNonce, const UA_ByteString *serverAppCert,
const UA_ByteString *serverChannelCert, const UA_ByteString *clientChannelCert,
UA_ByteString *out);
UA_StatusCode
UA_SecureChannel_buildUserTokenSignatureData(
const UA_SecureChannel *channel, const UA_ByteString *serverNonce,
const UA_ByteString *clientNonce, const UA_ByteString *serverAppCert,
const UA_ByteString *serverChannelCert, const UA_ByteString *clientAppCert,
const UA_ByteString *clientChannelCert, UA_ByteString *out);
void
UA_SecureChannel_sendERR(UA_SecureChannel *channel, UA_TcpErrorMessage *error);
UA_StatusCode
UA_SecureChannel_sendOPN(UA_SecureChannel *channel, UA_UInt32 requestId,
const void *content, const UA_DataType *contentType);
UA_StatusCode
UA_SecureChannel_sendMSG(UA_SecureChannel *channel, UA_UInt32 requestId,
void *payload, const UA_DataType *payloadType);
UA_StatusCode
UA_SecureChannel_sendCLO(UA_SecureChannel *channel, UA_UInt32 requestId,
UA_CloseSecureChannelRequest *req);
typedef struct {
UA_SecureChannel *channel;
UA_UInt32 requestId;
UA_UInt32 messageType;
UA_UInt16 chunksSoFar;
size_t messageSizeSoFar;
UA_ByteString messageBuffer;
UA_Byte *buf_pos;
const UA_Byte *buf_end;
UA_Boolean final;
} UA_MessageContext;
UA_StatusCode
UA_MessageContext_begin(UA_MessageContext *mc, UA_SecureChannel *channel,
UA_UInt32 requestId, UA_MessageType messageType);
UA_StatusCode
UA_MessageContext_encode(UA_MessageContext *mc, const void *content,
const UA_DataType *contentType);
UA_StatusCode
UA_MessageContext_finish(UA_MessageContext *mc);
void
UA_MessageContext_abort(UA_MessageContext *mc);
UA_StatusCode
UA_SecureChannel_loadBuffer(UA_SecureChannel *channel, const UA_ByteString buffer);
UA_StatusCode
UA_SecureChannel_getCompleteMessage(UA_SecureChannel *channel,
UA_MessageType *messageType, UA_UInt32 *requestId,
UA_ByteString *payload, UA_Boolean *copied,
UA_DateTime nowMonotonic);
UA_StatusCode
UA_SecureChannel_persistBuffer(UA_SecureChannel *channel);
void
hideBytesAsym(const UA_SecureChannel *channel, UA_Byte **buf_start,
const UA_Byte **buf_end);
UA_StatusCode
decryptAndVerifyChunk(UA_SecureChannel *channel,
const UA_SecurityPolicySignatureAlgorithm *signatureAlgorithm,
const UA_SecurityPolicyEncryptionAlgorithm *encryptionAlgorithm,
UA_MessageType messageType, UA_ByteString *chunk, size_t offset);
size_t
calculateAsymAlgSecurityHeaderLength(const UA_SecureChannel *channel);
UA_StatusCode
prependHeadersAsym(UA_SecureChannel *const channel, UA_Byte *header_pos,
const UA_Byte *buf_end, size_t totalLength,
size_t securityHeaderLength, UA_UInt32 requestId,
size_t *const finalLength);
UA_UInt32
UA_SecureChannel_nextSequenceNumber(UA_SecureChannel *channel);
void
setBufPos(UA_MessageContext *mc);
UA_StatusCode
checkSymHeader(UA_SecureChannel *channel, const UA_UInt32 tokenId,
UA_DateTime nowMonotonic);
UA_StatusCode
checkAsymHeader(UA_SecureChannel *channel,
const UA_AsymmetricAlgorithmSecurityHeader *asymHeader);
void
padChunk(UA_SecureChannel *channel,
const UA_SecurityPolicySignatureAlgorithm *signatureAlgorithm,
const UA_SecurityPolicyEncryptionAlgorithm *encryptionAlgorithm,
const UA_Byte *start, UA_Byte **pos);
UA_StatusCode
signAndEncryptAsym(UA_SecureChannel *channel, size_t preSignLength,
UA_ByteString *buf, size_t securityHeaderLength,
size_t totalLength);
UA_StatusCode
signAndEncryptSym(UA_MessageContext *messageContext,
size_t preSigLength, size_t totalLength);
#define UA_LOG_CHANNEL_INTERNAL(LOGGER, LEVEL, CHANNEL, MSG, ...) \
do { \
if(UA_LOGLEVEL <= UA_LOGLEVEL_##LEVEL) { \
UA_LOG_##LEVEL(LOGGER, UA_LOGCATEGORY_SECURECHANNEL, \
"TCP %lu\t| SC %" PRIu32 "\t| " MSG "%.0s", \
(long unsigned)(CHANNEL)->connectionId, \
(CHANNEL)->securityToken.channelId, __VA_ARGS__); \
} \
} while (0)
#define UA_LOG_TRACE_CHANNEL(LOGGER, CHANNEL, ...) \
UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, TRACE, CHANNEL, __VA_ARGS__, ""))
#define UA_LOG_DEBUG_CHANNEL(LOGGER, CHANNEL, ...) \
UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, DEBUG, CHANNEL, __VA_ARGS__, ""))
#define UA_LOG_INFO_CHANNEL(LOGGER, CHANNEL, ...) \
UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, INFO, CHANNEL, __VA_ARGS__, ""))
#define UA_LOG_WARNING_CHANNEL(LOGGER, CHANNEL, ...) \
UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, WARNING, CHANNEL, __VA_ARGS__, ""))
#define UA_LOG_ERROR_CHANNEL(LOGGER, CHANNEL, ...) \
UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, ERROR, CHANNEL, __VA_ARGS__, ""))
#define UA_LOG_FATAL_CHANNEL(LOGGER, CHANNEL, ...) \
UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, FATAL, CHANNEL, __VA_ARGS__, ""))
_UA_END_DECLS
#endif