|
@@ -14,7 +14,6 @@
|
|
|
|
|
|
#define UA_BITMASK_MESSAGETYPE 0x00ffffff
|
|
#define UA_BITMASK_MESSAGETYPE 0x00ffffff
|
|
#define UA_BITMASK_CHUNKTYPE 0xff000000
|
|
#define UA_BITMASK_CHUNKTYPE 0xff000000
|
|
-#define UA_SECURE_MESSAGE_HEADER_LENGTH 24
|
|
|
|
#define UA_ASYMMETRIC_ALG_SECURITY_HEADER_FIXED_LENGTH 12
|
|
#define UA_ASYMMETRIC_ALG_SECURITY_HEADER_FIXED_LENGTH 12
|
|
#define UA_SYMMETRIC_ALG_SECURITY_HEADER_LENGTH 4
|
|
#define UA_SYMMETRIC_ALG_SECURITY_HEADER_LENGTH 4
|
|
#define UA_SEQUENCE_HEADER_LENGTH 8
|
|
#define UA_SEQUENCE_HEADER_LENGTH 8
|
|
@@ -31,27 +30,13 @@ UA_THREAD_LOCAL UA_StatusCode sendAsym_sendFailure;
|
|
UA_THREAD_LOCAL UA_StatusCode processSym_seqNumberFailure;
|
|
UA_THREAD_LOCAL UA_StatusCode processSym_seqNumberFailure;
|
|
#endif
|
|
#endif
|
|
|
|
|
|
-/* Callback data for sending responses in multiple chunks */
|
|
|
|
-typedef struct {
|
|
|
|
- UA_SecureChannel *channel;
|
|
|
|
- UA_UInt32 requestId;
|
|
|
|
- UA_UInt32 messageType;
|
|
|
|
-
|
|
|
|
- UA_UInt16 chunksSoFar;
|
|
|
|
- size_t messageSizeSoFar;
|
|
|
|
-
|
|
|
|
- UA_ByteString messageBuffer;
|
|
|
|
- UA_Boolean final;
|
|
|
|
-} UA_ChunkInfo;
|
|
|
|
-
|
|
|
|
UA_StatusCode
|
|
UA_StatusCode
|
|
UA_SecureChannel_init(UA_SecureChannel *channel,
|
|
UA_SecureChannel_init(UA_SecureChannel *channel,
|
|
const UA_SecurityPolicy *securityPolicy,
|
|
const UA_SecurityPolicy *securityPolicy,
|
|
const UA_ByteString *remoteCertificate) {
|
|
const UA_ByteString *remoteCertificate) {
|
|
|
|
|
|
- if(channel == NULL || securityPolicy == NULL || remoteCertificate == NULL) {
|
|
|
|
|
|
+ if(channel == NULL || securityPolicy == NULL || remoteCertificate == NULL)
|
|
return UA_STATUSCODE_BADINTERNALERROR;
|
|
return UA_STATUSCODE_BADINTERNALERROR;
|
|
- }
|
|
|
|
|
|
|
|
memset(channel, 0, sizeof(UA_SecureChannel));
|
|
memset(channel, 0, sizeof(UA_SecureChannel));
|
|
channel->state = UA_SECURECHANNELSTATE_FRESH;
|
|
channel->state = UA_SECURECHANNELSTATE_FRESH;
|
|
@@ -252,8 +237,8 @@ calculatePaddingAsym(const UA_SecurityPolicy *securityPolicy, const void *channe
|
|
size_t signatureSize = securityPolicy->asymmetricModule.cryptoModule.
|
|
size_t signatureSize = securityPolicy->asymmetricModule.cryptoModule.
|
|
getLocalSignatureSize(securityPolicy, channelContext);
|
|
getLocalSignatureSize(securityPolicy, channelContext);
|
|
size_t paddingBytes = 1;
|
|
size_t paddingBytes = 1;
|
|
- if(securityPolicy->asymmetricModule.cryptoModule.getRemoteEncryptionKeyLength(securityPolicy,
|
|
|
|
- channelContext) > 2048)
|
|
|
|
|
|
+ if(securityPolicy->asymmetricModule.cryptoModule.
|
|
|
|
+ getRemoteEncryptionKeyLength(securityPolicy, channelContext) > 2048)
|
|
++paddingBytes;
|
|
++paddingBytes;
|
|
size_t padding = (plainTextBlockSize - ((bytesToWrite + signatureSize + paddingBytes) % plainTextBlockSize));
|
|
size_t padding = (plainTextBlockSize - ((bytesToWrite + signatureSize + paddingBytes) % plainTextBlockSize));
|
|
*paddingSize = (UA_Byte) (padding & 0xff);
|
|
*paddingSize = (UA_Byte) (padding & 0xff);
|
|
@@ -292,9 +277,9 @@ hideBytesAsym(UA_SecureChannel *const channel, UA_Byte **const buf_start,
|
|
*buf_end -= 2; // padding byte and extraPadding byte
|
|
*buf_end -= 2; // padding byte and extraPadding byte
|
|
|
|
|
|
/* Add some overhead length due to RSA implementations adding a signature themselves */
|
|
/* Add some overhead length due to RSA implementations adding a signature themselves */
|
|
- *buf_end -= securityPolicy->channelModule
|
|
|
|
- .getRemoteAsymEncryptionBufferLengthOverhead(channel->channelContext,
|
|
|
|
- potentialEncryptionMaxSize);
|
|
|
|
|
|
+ *buf_end -= securityPolicy->channelModule.
|
|
|
|
+ getRemoteAsymEncryptionBufferLengthOverhead(channel->channelContext,
|
|
|
|
+ potentialEncryptionMaxSize);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -358,9 +343,8 @@ UA_SecureChannel_sendAsymmetricOPNMessage(UA_SecureChannel *channel, UA_UInt32 r
|
|
*buf_pos = paddingSize;
|
|
*buf_pos = paddingSize;
|
|
++buf_pos;
|
|
++buf_pos;
|
|
}
|
|
}
|
|
- if(securityPolicy->asymmetricModule.cryptoModule.getRemoteEncryptionKeyLength(securityPolicy,
|
|
|
|
- channel->channelContext)
|
|
|
|
- > 2048) {
|
|
|
|
|
|
+ if(securityPolicy->asymmetricModule.cryptoModule.
|
|
|
|
+ getRemoteEncryptionKeyLength(securityPolicy, channel->channelContext) > 2048) {
|
|
*buf_pos = extraPaddingSize;
|
|
*buf_pos = extraPaddingSize;
|
|
++buf_pos;
|
|
++buf_pos;
|
|
}
|
|
}
|
|
@@ -465,35 +449,49 @@ calculatePaddingSym(const UA_SecurityPolicy *securityPolicy, const void *channel
|
|
return padding;
|
|
return padding;
|
|
}
|
|
}
|
|
|
|
|
|
-/* Sends a message using symmetric encryption if defined
|
|
|
|
- *
|
|
|
|
- * @param ci the chunk information that is used to send the chunk.
|
|
|
|
- * @param buf_pos the position in the send buffer after the body was encoded.
|
|
|
|
- * Should be less than or equal to buf_end.
|
|
|
|
- * @param buf_end the maximum position of the body. */
|
|
|
|
|
|
+static void
|
|
|
|
+setBufPos(UA_MessageContext *mc) {
|
|
|
|
+ const UA_SecureChannel *channel= mc->channel;
|
|
|
|
+ const UA_SecurityPolicy *securityPolicy = channel->securityPolicy;
|
|
|
|
+
|
|
|
|
+ /* Forward the data pointer so that the payload is encoded after the
|
|
|
|
+ * message header */
|
|
|
|
+ mc->buf_pos = &mc->messageBuffer.data[UA_SECURE_MESSAGE_HEADER_LENGTH];
|
|
|
|
+ mc->buf_end = &mc->messageBuffer.data[mc->messageBuffer.length];
|
|
|
|
+
|
|
|
|
+ if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
|
|
|
|
+ channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
|
|
|
|
+ mc->buf_end -= securityPolicy->symmetricModule.cryptoModule.
|
|
|
|
+ getLocalSignatureSize(securityPolicy, channel->channelContext);
|
|
|
|
+
|
|
|
|
+ /* Hide a byte needed for padding */
|
|
|
|
+ if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
|
|
|
|
+ mc->buf_end -= 2;
|
|
|
|
+}
|
|
|
|
+
|
|
static UA_StatusCode
|
|
static UA_StatusCode
|
|
-sendChunkSymmetric(UA_ChunkInfo *ci, UA_Byte **buf_pos, const UA_Byte **buf_end) {
|
|
|
|
|
|
+sendSymmetricChunk(UA_MessageContext *mc) {
|
|
UA_StatusCode res = UA_STATUSCODE_GOOD;
|
|
UA_StatusCode res = UA_STATUSCODE_GOOD;
|
|
- UA_SecureChannel *const channel = ci->channel;
|
|
|
|
|
|
+ UA_SecureChannel *const channel = mc->channel;
|
|
const UA_SecurityPolicy *securityPolicy = channel->securityPolicy;
|
|
const UA_SecurityPolicy *securityPolicy = channel->securityPolicy;
|
|
UA_Connection *const connection = channel->connection;
|
|
UA_Connection *const connection = channel->connection;
|
|
if(!connection)
|
|
if(!connection)
|
|
return UA_STATUSCODE_BADINTERNALERROR;
|
|
return UA_STATUSCODE_BADINTERNALERROR;
|
|
|
|
|
|
/* Will this chunk surpass the capacity of the SecureChannel for the message? */
|
|
/* Will this chunk surpass the capacity of the SecureChannel for the message? */
|
|
- UA_Byte *buf_body_start = ci->messageBuffer.data + UA_SECURE_MESSAGE_HEADER_LENGTH;
|
|
|
|
- UA_Byte *buf_body_end = *buf_pos;
|
|
|
|
|
|
+ UA_Byte *buf_body_start = mc->messageBuffer.data + UA_SECURE_MESSAGE_HEADER_LENGTH;
|
|
|
|
+ const UA_Byte *buf_body_end = mc->buf_pos;
|
|
size_t bodyLength = (uintptr_t) buf_body_end - (uintptr_t) buf_body_start;
|
|
size_t bodyLength = (uintptr_t) buf_body_end - (uintptr_t) buf_body_start;
|
|
- ci->messageSizeSoFar += bodyLength;
|
|
|
|
- ci->chunksSoFar++;
|
|
|
|
- if(ci->messageSizeSoFar > connection->remoteConf.maxMessageSize &&
|
|
|
|
|
|
+ mc->messageSizeSoFar += bodyLength;
|
|
|
|
+ mc->chunksSoFar++;
|
|
|
|
+ if(mc->messageSizeSoFar > connection->remoteConf.maxMessageSize &&
|
|
connection->remoteConf.maxMessageSize != 0)
|
|
connection->remoteConf.maxMessageSize != 0)
|
|
res = UA_STATUSCODE_BADRESPONSETOOLARGE;
|
|
res = UA_STATUSCODE_BADRESPONSETOOLARGE;
|
|
- if(ci->chunksSoFar > connection->remoteConf.maxChunkCount &&
|
|
|
|
|
|
+ if(mc->chunksSoFar > connection->remoteConf.maxChunkCount &&
|
|
connection->remoteConf.maxChunkCount != 0)
|
|
connection->remoteConf.maxChunkCount != 0)
|
|
res = UA_STATUSCODE_BADRESPONSETOOLARGE;
|
|
res = UA_STATUSCODE_BADRESPONSETOOLARGE;
|
|
if(res != UA_STATUSCODE_GOOD) {
|
|
if(res != UA_STATUSCODE_GOOD) {
|
|
- connection->releaseSendBuffer(channel->connection, &ci->messageBuffer);
|
|
|
|
|
|
+ connection->releaseSendBuffer(channel->connection, &mc->messageBuffer);
|
|
return res;
|
|
return res;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -509,58 +507,59 @@ sendChunkSymmetric(UA_ChunkInfo *ci, UA_Byte **buf_pos, const UA_Byte **buf_end)
|
|
|
|
|
|
// This is <= because the paddingSize byte also has to be written.
|
|
// This is <= because the paddingSize byte also has to be written.
|
|
for(UA_UInt16 i = 0; i <= totalPaddingSize; ++i) {
|
|
for(UA_UInt16 i = 0; i <= totalPaddingSize; ++i) {
|
|
- **buf_pos = paddingSize;
|
|
|
|
- ++(*buf_pos);
|
|
|
|
|
|
+ *mc->buf_pos = paddingSize;
|
|
|
|
+ ++(mc->buf_pos);
|
|
}
|
|
}
|
|
if(extraPaddingSize > 0) {
|
|
if(extraPaddingSize > 0) {
|
|
- **buf_pos = extraPaddingSize;
|
|
|
|
- ++(*buf_pos);
|
|
|
|
|
|
+ *mc->buf_pos = extraPaddingSize;
|
|
|
|
+ ++(mc->buf_pos);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* The total message length */
|
|
/* The total message length */
|
|
- size_t pre_sig_length = (uintptr_t) (*buf_pos) - (uintptr_t) ci->messageBuffer.data;
|
|
|
|
|
|
+ size_t pre_sig_length = (uintptr_t) (mc->buf_pos) - (uintptr_t) mc->messageBuffer.data;
|
|
size_t total_length = pre_sig_length;
|
|
size_t total_length = pre_sig_length;
|
|
if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
|
|
if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
|
|
channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
|
|
channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
|
|
total_length += securityPolicy->symmetricModule.cryptoModule.
|
|
total_length += securityPolicy->symmetricModule.cryptoModule.
|
|
getLocalSignatureSize(securityPolicy, channel->channelContext);
|
|
getLocalSignatureSize(securityPolicy, channel->channelContext);
|
|
|
|
+ mc->messageBuffer.length = total_length; /* For giving the buffer to the network layer */
|
|
|
|
|
|
/* Encode the chunk headers at the beginning of the buffer */
|
|
/* Encode the chunk headers at the beginning of the buffer */
|
|
UA_assert(res == UA_STATUSCODE_GOOD);
|
|
UA_assert(res == UA_STATUSCODE_GOOD);
|
|
- UA_Byte *header_pos = ci->messageBuffer.data;
|
|
|
|
|
|
+ UA_Byte *header_pos = mc->messageBuffer.data;
|
|
UA_SecureConversationMessageHeader respHeader;
|
|
UA_SecureConversationMessageHeader respHeader;
|
|
respHeader.secureChannelId = channel->securityToken.channelId;
|
|
respHeader.secureChannelId = channel->securityToken.channelId;
|
|
- respHeader.messageHeader.messageTypeAndChunkType = ci->messageType;
|
|
|
|
- respHeader.messageHeader.messageSize = (UA_UInt32) total_length;
|
|
|
|
- if(ci->final)
|
|
|
|
|
|
+ respHeader.messageHeader.messageTypeAndChunkType = mc->messageType;
|
|
|
|
+ respHeader.messageHeader.messageSize = (UA_UInt32)total_length;
|
|
|
|
+ if(mc->final)
|
|
respHeader.messageHeader.messageTypeAndChunkType += UA_CHUNKTYPE_FINAL;
|
|
respHeader.messageHeader.messageTypeAndChunkType += UA_CHUNKTYPE_FINAL;
|
|
else
|
|
else
|
|
respHeader.messageHeader.messageTypeAndChunkType += UA_CHUNKTYPE_INTERMEDIATE;
|
|
respHeader.messageHeader.messageTypeAndChunkType += UA_CHUNKTYPE_INTERMEDIATE;
|
|
res = UA_encodeBinary(&respHeader, &UA_TRANSPORT[UA_TRANSPORT_SECURECONVERSATIONMESSAGEHEADER],
|
|
res = UA_encodeBinary(&respHeader, &UA_TRANSPORT[UA_TRANSPORT_SECURECONVERSATIONMESSAGEHEADER],
|
|
- &header_pos, buf_end, NULL, NULL);
|
|
|
|
|
|
+ &header_pos, &mc->buf_end, NULL, NULL);
|
|
|
|
|
|
UA_SymmetricAlgorithmSecurityHeader symSecHeader;
|
|
UA_SymmetricAlgorithmSecurityHeader symSecHeader;
|
|
symSecHeader.tokenId = channel->securityToken.tokenId;
|
|
symSecHeader.tokenId = channel->securityToken.tokenId;
|
|
res |= UA_encodeBinary(&symSecHeader.tokenId,
|
|
res |= UA_encodeBinary(&symSecHeader.tokenId,
|
|
&UA_TRANSPORT[UA_TRANSPORT_SYMMETRICALGORITHMSECURITYHEADER],
|
|
&UA_TRANSPORT[UA_TRANSPORT_SYMMETRICALGORITHMSECURITYHEADER],
|
|
- &header_pos, buf_end, NULL, NULL);
|
|
|
|
|
|
+ &header_pos, &mc->buf_end, NULL, NULL);
|
|
|
|
|
|
UA_SequenceHeader seqHeader;
|
|
UA_SequenceHeader seqHeader;
|
|
- seqHeader.requestId = ci->requestId;
|
|
|
|
|
|
+ seqHeader.requestId = mc->requestId;
|
|
seqHeader.sequenceNumber = UA_atomic_add(&channel->sendSequenceNumber, 1);
|
|
seqHeader.sequenceNumber = UA_atomic_add(&channel->sendSequenceNumber, 1);
|
|
res |= UA_encodeBinary(&seqHeader, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER],
|
|
res |= UA_encodeBinary(&seqHeader, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER],
|
|
- &header_pos, buf_end, NULL, NULL);
|
|
|
|
|
|
+ &header_pos, &mc->buf_end, NULL, NULL);
|
|
|
|
|
|
/* Sign message */
|
|
/* Sign message */
|
|
if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
|
|
if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
|
|
channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
|
|
channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
|
|
- UA_ByteString dataToSign = ci->messageBuffer;
|
|
|
|
|
|
+ UA_ByteString dataToSign = mc->messageBuffer;
|
|
dataToSign.length = pre_sig_length;
|
|
dataToSign.length = pre_sig_length;
|
|
UA_ByteString signature;
|
|
UA_ByteString signature;
|
|
signature.length = securityPolicy->symmetricModule.cryptoModule.
|
|
signature.length = securityPolicy->symmetricModule.cryptoModule.
|
|
getLocalSignatureSize(securityPolicy, channel->channelContext);
|
|
getLocalSignatureSize(securityPolicy, channel->channelContext);
|
|
- signature.data = *buf_pos;
|
|
|
|
|
|
+ signature.data = mc->buf_pos;
|
|
res |= securityPolicy->symmetricModule.cryptoModule.
|
|
res |= securityPolicy->symmetricModule.cryptoModule.
|
|
sign(securityPolicy, channel->channelContext, &dataToSign, &signature);
|
|
sign(securityPolicy, channel->channelContext, &dataToSign, &signature);
|
|
}
|
|
}
|
|
@@ -568,115 +567,130 @@ sendChunkSymmetric(UA_ChunkInfo *ci, UA_Byte **buf_pos, const UA_Byte **buf_end)
|
|
/* Encrypt message */
|
|
/* Encrypt message */
|
|
if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
|
|
if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
|
|
UA_ByteString dataToEncrypt;
|
|
UA_ByteString dataToEncrypt;
|
|
- dataToEncrypt.data = ci->messageBuffer.data + UA_SECUREMH_AND_SYMALGH_LENGTH;
|
|
|
|
|
|
+ dataToEncrypt.data = mc->messageBuffer.data + UA_SECUREMH_AND_SYMALGH_LENGTH;
|
|
dataToEncrypt.length = total_length - UA_SECUREMH_AND_SYMALGH_LENGTH;
|
|
dataToEncrypt.length = total_length - UA_SECUREMH_AND_SYMALGH_LENGTH;
|
|
res |= securityPolicy->symmetricModule.cryptoModule.
|
|
res |= securityPolicy->symmetricModule.cryptoModule.
|
|
encrypt(securityPolicy, channel->channelContext, &dataToEncrypt);
|
|
encrypt(securityPolicy, channel->channelContext, &dataToEncrypt);
|
|
}
|
|
}
|
|
|
|
|
|
if(res != UA_STATUSCODE_GOOD) {
|
|
if(res != UA_STATUSCODE_GOOD) {
|
|
- connection->releaseSendBuffer(channel->connection, &ci->messageBuffer);
|
|
|
|
|
|
+ connection->releaseSendBuffer(channel->connection, &mc->messageBuffer);
|
|
return res;
|
|
return res;
|
|
}
|
|
}
|
|
|
|
|
|
/* Send the chunk, the buffer is freed in the network layer */
|
|
/* Send the chunk, the buffer is freed in the network layer */
|
|
- ci->messageBuffer.length = respHeader.messageHeader.messageSize;
|
|
|
|
- res = connection->send(channel->connection, &ci->messageBuffer);
|
|
|
|
- if(res != UA_STATUSCODE_GOOD)
|
|
|
|
- return res;
|
|
|
|
|
|
+ return connection->send(channel->connection, &mc->messageBuffer);
|
|
|
|
+}
|
|
|
|
|
|
- /* Replace with the buffer for the next chunk */
|
|
|
|
- if(!ci->final) {
|
|
|
|
- res = connection->getSendBuffer(connection, connection->localConf.sendBufferSize,
|
|
|
|
- &ci->messageBuffer);
|
|
|
|
- if(res != UA_STATUSCODE_GOOD)
|
|
|
|
- return res;
|
|
|
|
-
|
|
|
|
- /* Forward the data pointer so that the payload is encoded after the
|
|
|
|
- * message header */
|
|
|
|
- *buf_pos = &ci->messageBuffer.data[UA_SECURE_MESSAGE_HEADER_LENGTH];
|
|
|
|
- *buf_end = &ci->messageBuffer.data[ci->messageBuffer.length];
|
|
|
|
-
|
|
|
|
- if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
|
|
|
|
- channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
|
|
|
|
- *buf_end -= securityPolicy->symmetricModule.cryptoModule.
|
|
|
|
- getLocalSignatureSize(securityPolicy, channel->channelContext);
|
|
|
|
-
|
|
|
|
- /* Hide a byte needed for padding */
|
|
|
|
- if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
|
|
|
|
- *buf_end -= 2;
|
|
|
|
- }
|
|
|
|
- return res;
|
|
|
|
|
|
+/* Callback from the encoding layer. Send the chunk and replace the buffer. */
|
|
|
|
+static UA_StatusCode
|
|
|
|
+sendSymmetricEncodingCallback(void *data, UA_Byte **buf_pos, const UA_Byte **buf_end) {
|
|
|
|
+ /* Set buf values from encoding in the messagecontext */
|
|
|
|
+ UA_MessageContext *mc = (UA_MessageContext*)data;
|
|
|
|
+ mc->buf_pos = *buf_pos;
|
|
|
|
+ mc->buf_end = *buf_end;
|
|
|
|
+
|
|
|
|
+ /* Send out */
|
|
|
|
+ UA_StatusCode retval = sendSymmetricChunk(mc);
|
|
|
|
+ if(retval != UA_STATUSCODE_GOOD)
|
|
|
|
+ return retval;
|
|
|
|
+
|
|
|
|
+ /* Set a new buffer for the next chunk */
|
|
|
|
+ UA_Connection *connection = mc->channel->connection;
|
|
|
|
+ retval = connection->getSendBuffer(connection, connection->localConf.sendBufferSize,
|
|
|
|
+ &mc->messageBuffer);
|
|
|
|
+ if(retval != UA_STATUSCODE_GOOD)
|
|
|
|
+ return retval;
|
|
|
|
+
|
|
|
|
+ /* Hide bytes for header, padding and signature */
|
|
|
|
+ setBufPos(mc);
|
|
|
|
+ *buf_pos = mc->buf_pos;
|
|
|
|
+ *buf_end = mc->buf_end;
|
|
|
|
+ return UA_STATUSCODE_GOOD;
|
|
}
|
|
}
|
|
|
|
|
|
UA_StatusCode
|
|
UA_StatusCode
|
|
-UA_SecureChannel_sendSymmetricMessage(UA_SecureChannel *channel, UA_UInt32 requestId,
|
|
|
|
- UA_MessageType messageType, const void *content,
|
|
|
|
- const UA_DataType *contentType) {
|
|
|
|
- const UA_SecurityPolicy *const securityPolicy = channel->securityPolicy;
|
|
|
|
|
|
+UA_MessageContext_begin(UA_MessageContext *mc, UA_SecureChannel *channel,
|
|
|
|
+ UA_UInt32 requestId, UA_MessageType messageType) {
|
|
UA_Connection *connection = channel->connection;
|
|
UA_Connection *connection = channel->connection;
|
|
if(!connection)
|
|
if(!connection)
|
|
return UA_STATUSCODE_BADINTERNALERROR;
|
|
return UA_STATUSCODE_BADINTERNALERROR;
|
|
|
|
|
|
|
|
+ /* Create the chunking info structure */
|
|
|
|
+ mc->channel = channel;
|
|
|
|
+ mc->requestId = requestId;
|
|
|
|
+ mc->chunksSoFar = 0;
|
|
|
|
+ mc->messageSizeSoFar = 0;
|
|
|
|
+ mc->final = false;
|
|
|
|
+ mc->messageBuffer = UA_BYTESTRING_NULL;
|
|
|
|
+ mc->messageType = messageType;
|
|
|
|
+
|
|
/* Minimum required size */
|
|
/* Minimum required size */
|
|
if(connection->localConf.sendBufferSize <= UA_SECURE_MESSAGE_HEADER_LENGTH)
|
|
if(connection->localConf.sendBufferSize <= UA_SECURE_MESSAGE_HEADER_LENGTH)
|
|
return UA_STATUSCODE_BADRESPONSETOOLARGE;
|
|
return UA_STATUSCODE_BADRESPONSETOOLARGE;
|
|
|
|
|
|
- /* Create the chunking info structure */
|
|
|
|
- UA_ChunkInfo ci;
|
|
|
|
- ci.channel = channel;
|
|
|
|
- ci.requestId = requestId;
|
|
|
|
- ci.chunksSoFar = 0;
|
|
|
|
- ci.messageSizeSoFar = 0;
|
|
|
|
- ci.final = false;
|
|
|
|
- ci.messageBuffer = UA_BYTESTRING_NULL;
|
|
|
|
- ci.messageType = messageType;
|
|
|
|
-
|
|
|
|
/* Allocate the message buffer */
|
|
/* Allocate the message buffer */
|
|
UA_StatusCode retval =
|
|
UA_StatusCode retval =
|
|
connection->getSendBuffer(connection, connection->localConf.sendBufferSize,
|
|
connection->getSendBuffer(connection, connection->localConf.sendBufferSize,
|
|
- &ci.messageBuffer);
|
|
|
|
|
|
+ &mc->messageBuffer);
|
|
if(retval != UA_STATUSCODE_GOOD)
|
|
if(retval != UA_STATUSCODE_GOOD)
|
|
return retval;
|
|
return retval;
|
|
|
|
|
|
- /* Hide the message beginning where the header will be encoded */
|
|
|
|
- UA_Byte *buf_start = &ci.messageBuffer.data[UA_SECURE_MESSAGE_HEADER_LENGTH];
|
|
|
|
- const UA_Byte *buf_end = &ci.messageBuffer.data[ci.messageBuffer.length];
|
|
|
|
|
|
+ /* Hide bytes for header, padding and signature */
|
|
|
|
+ setBufPos(mc);
|
|
|
|
+ return UA_STATUSCODE_GOOD;
|
|
|
|
+}
|
|
|
|
|
|
- /* Hide bytes for signature */
|
|
|
|
- if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
|
|
|
|
- channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
|
|
|
|
- buf_end -= securityPolicy->symmetricModule.cryptoModule.
|
|
|
|
- getLocalSignatureSize(securityPolicy, channel->channelContext);
|
|
|
|
|
|
+UA_StatusCode
|
|
|
|
+UA_MessageContext_encode(UA_MessageContext *mc, const void *content,
|
|
|
|
+ const UA_DataType *contentType) {
|
|
|
|
+ UA_StatusCode retval = UA_encodeBinary(content, contentType, &mc->buf_pos, &mc->buf_end,
|
|
|
|
+ sendSymmetricEncodingCallback, mc);
|
|
|
|
+ if(retval != UA_STATUSCODE_GOOD) {
|
|
|
|
+ /* TODO: Send the abort message */
|
|
|
|
+ if(mc->messageBuffer.length > 0) {
|
|
|
|
+ UA_Connection *connection = mc->channel->connection;
|
|
|
|
+ connection->releaseSendBuffer(connection, &mc->messageBuffer);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return retval;
|
|
|
|
+}
|
|
|
|
|
|
- /* Hide one byte for padding */
|
|
|
|
- if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
|
|
|
|
- buf_end -= 2;
|
|
|
|
|
|
+UA_StatusCode
|
|
|
|
+UA_MessageContext_finish(UA_MessageContext *mc) {
|
|
|
|
+ mc->final = true;
|
|
|
|
+ return sendSymmetricChunk(mc);
|
|
|
|
+}
|
|
|
|
|
|
- /* Encode the message type */
|
|
|
|
- UA_NodeId typeId = UA_NODEID_NUMERIC(0, contentType->binaryEncodingId);
|
|
|
|
- retval = UA_encodeBinary(&typeId, &UA_TYPES[UA_TYPES_NODEID],
|
|
|
|
- &buf_start, &buf_end, NULL, NULL);
|
|
|
|
|
|
+void
|
|
|
|
+UA_MessageContext_abort(UA_MessageContext *mc) {
|
|
|
|
+ UA_ByteString_deleteMembers(&mc->messageBuffer);
|
|
|
|
+}
|
|
|
|
|
|
- /* Encode with the chunking callback */
|
|
|
|
- retval |= UA_encodeBinary(content, contentType, &buf_start, &buf_end,
|
|
|
|
- (UA_exchangeEncodeBuffer) sendChunkSymmetric, &ci);
|
|
|
|
|
|
+UA_StatusCode
|
|
|
|
+UA_SecureChannel_sendSymmetricMessage(UA_SecureChannel *channel, UA_UInt32 requestId,
|
|
|
|
+ UA_MessageType messageType, void *payload,
|
|
|
|
+ const UA_DataType *payloadType) {
|
|
|
|
+ UA_MessageContext mc;
|
|
|
|
+ UA_StatusCode retval;
|
|
|
|
+ UA_NodeId typeId = UA_NODEID_NUMERIC(0, payloadType->binaryEncodingId);
|
|
|
|
+ retval = UA_MessageContext_begin(&mc, channel, requestId, UA_MESSAGETYPE_MSG);
|
|
|
|
+ if(retval != UA_STATUSCODE_GOOD)
|
|
|
|
+ return retval;
|
|
|
|
|
|
- /* TODO: Error handling. Send out an abort chunk if this is not the first chunk.
|
|
|
|
- * If this is the first chunk of the message:
|
|
|
|
- * - Client: Do nothing, maybe revert the sequence number?
|
|
|
|
- * - Server: Send a ServiceFault response? Depending on which error codes? */
|
|
|
|
- if(retval != UA_STATUSCODE_GOOD) {
|
|
|
|
- /* the abort message was not sent */
|
|
|
|
- if(!ci.final)
|
|
|
|
- sendChunkSymmetric(&ci, &buf_start, &buf_end);
|
|
|
|
- connection->releaseSendBuffer(connection, &ci.messageBuffer);
|
|
|
|
|
|
+ /* Assert's required for clang-analyzer */
|
|
|
|
+ UA_assert(mc.buf_pos == &mc.messageBuffer.data[UA_SECURE_MESSAGE_HEADER_LENGTH]);
|
|
|
|
+ UA_assert(mc.buf_end == &mc.messageBuffer.data[mc.messageBuffer.length]);
|
|
|
|
+
|
|
|
|
+ retval |= UA_MessageContext_encode(&mc, &typeId, &UA_TYPES[UA_TYPES_NODEID]);
|
|
|
|
+ if(retval != UA_STATUSCODE_GOOD)
|
|
|
|
+ return retval;
|
|
|
|
+
|
|
|
|
+ retval |= UA_MessageContext_encode(&mc, payload, payloadType);
|
|
|
|
+ if(retval != UA_STATUSCODE_GOOD)
|
|
return retval;
|
|
return retval;
|
|
- }
|
|
|
|
|
|
|
|
- /* Encoding finished, send the final chunk */
|
|
|
|
- ci.final = UA_TRUE;
|
|
|
|
- return sendChunkSymmetric(&ci, &buf_start, &buf_end);
|
|
|
|
|
|
+ return UA_MessageContext_finish(&mc);
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************/
|
|
/*****************************/
|
|
@@ -794,8 +808,7 @@ decryptChunk(UA_SecureChannel *channel, const UA_SecurityPolicyCryptoModule *cry
|
|
channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT ||
|
|
channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT ||
|
|
messageType == UA_MESSAGETYPE_OPN) {
|
|
messageType == UA_MESSAGETYPE_OPN) {
|
|
/* Compute the padding size */
|
|
/* Compute the padding size */
|
|
- sigsize = cryptoModule->
|
|
|
|
- getRemoteSignatureSize(securityPolicy, channel->channelContext);
|
|
|
|
|
|
+ sigsize = cryptoModule-> getRemoteSignatureSize(securityPolicy, channel->channelContext);
|
|
|
|
|
|
if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT ||
|
|
if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT ||
|
|
(messageType == UA_MESSAGETYPE_OPN &&
|
|
(messageType == UA_MESSAGETYPE_OPN &&
|
|
@@ -803,7 +816,7 @@ decryptChunk(UA_SecureChannel *channel, const UA_SecurityPolicyCryptoModule *cry
|
|
paddingSize = chunk->data[chunkSizeAfterDecryption - sigsize - 1];
|
|
paddingSize = chunk->data[chunkSizeAfterDecryption - sigsize - 1];
|
|
|
|
|
|
size_t keyLength = cryptoModule->
|
|
size_t keyLength = cryptoModule->
|
|
- getRemoteEncryptionKeyLength(securityPolicy, channel->channelContext);
|
|
|
|
|
|
+ getRemoteEncryptionKeyLength(securityPolicy, channel->channelContext);
|
|
if(keyLength > 2048) {
|
|
if(keyLength > 2048) {
|
|
paddingSize <<= 8; /* Extra padding size */
|
|
paddingSize <<= 8; /* Extra padding size */
|
|
paddingSize += chunk->data[chunkSizeAfterDecryption - sigsize - 2];
|
|
paddingSize += chunk->data[chunkSizeAfterDecryption - sigsize - 2];
|