Skip to content

Commit

Permalink
feat(test): Add pubsub encryption unit test for FPM
Browse files Browse the repository at this point in the history
Signed-off-by: Keerthivasan Alagarsamy Senthilkumaran <keerthivasan.as@kalycito.com>
Change-Id: I68ba90d47461c5f16f774ec37c89d31006081c47
  • Loading branch information
opcua-tsn-team-kalycito authored and jpfr committed Nov 16, 2021
1 parent c3b252f commit fbc0253
Show file tree
Hide file tree
Showing 12 changed files with 1,027 additions and 67 deletions.
37 changes: 32 additions & 5 deletions examples/pubsub_realtime/pubsub_TSN_loopback.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,11 @@ UA_DataSetReaderConfig readerConfig;
#define MILLI_SECONDS 1000 * 1000
#define SECONDS 1000 * 1000 * 1000
#define SECONDS_SLEEP 5
#if defined(PUBLISHER)
/* Publisher will sleep for 60% of cycle time and then prepares the */
/* transmission packet within 40% */
static UA_Double pubWakeupPercentage = 0.6;
#endif
/* Subscriber will wakeup only during start of cycle and check whether */
/* the packets are received */
static UA_Double subWakeupPercentage = 0;
Expand Down Expand Up @@ -154,14 +156,18 @@ static UA_Double userAppWakeupPercentage = 0.3;
#define UA_AES128CTR_KEY_LENGTH 16
#define UA_AES128CTR_KEYNONCE_LENGTH 4

#if defined(PUBLISHER)
UA_Byte signingKeyPub[UA_AES128CTR_SIGNING_KEY_LENGTH] = {0};
UA_Byte encryptingKeyPub[UA_AES128CTR_KEY_LENGTH] = {0};
UA_Byte keyNoncePub[UA_AES128CTR_KEYNONCE_LENGTH] = {0};
#endif

#if defined(SUBSCRIBER)
UA_Byte signingKeySub[UA_AES128CTR_SIGNING_KEY_LENGTH] = {0};
UA_Byte encryptingKeySub[UA_AES128CTR_KEY_LENGTH] = {0};
UA_Byte keyNonceSub[UA_AES128CTR_KEYNONCE_LENGTH] = {0};
#endif
#endif

/* If the Hardcoded publisher/subscriber MAC addresses need to be changed,
* change PUBLISHING_MAC_ADDRESS and SUBSCRIBING_MAC_ADDRESS
Expand Down Expand Up @@ -471,7 +477,7 @@ addReaderGroup(UA_Server *server) {
/* Encryption settings */
UA_ServerConfig *config = UA_Server_getConfig(server);
readerGroupConfig.securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT;
readerGroupConfig.securityPolicy = &config->pubSubConfig.securityPolicies[1];
readerGroupConfig.securityPolicy = &config->pubSubConfig.securityPolicies[0];
#endif

readerGroupConfig.pubsubManagerCallback.addCustomCallback = addPubSubApplicationCallback;
Expand Down Expand Up @@ -845,7 +851,7 @@ addWriterGroup(UA_Server *server) {
#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
UA_ServerConfig *config = UA_Server_getConfig(server);
writerGroupConfig.securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT;
writerGroupConfig.securityPolicy = &config->pubSubConfig.securityPolicies[0];
writerGroupConfig.securityPolicy = &config->pubSubConfig.securityPolicies[1];
#endif
/* The configuration flags for the messages are encapsulated inside the
* message- and transport settings extension objects. These extension
Expand Down Expand Up @@ -938,6 +944,7 @@ updateMeasurementsSubscriber(struct timespec receive_time, UA_UInt64 counterValu
}
#endif

#if defined(PUBLISHER)
/**
* **Publisher thread routine**
*
Expand Down Expand Up @@ -1016,6 +1023,7 @@ void *publisherETF(void *arg) {
runningServer = UA_FALSE;
return (void*)NULL;
}
#endif

#if defined(SUBSCRIBER)
/**
Expand Down Expand Up @@ -1072,6 +1080,9 @@ void *subscriber(void *arg) {
if (*runningSub == UA_FALSE)
signalTerm = UA_TRUE;

#if defined(SUBSCRIBER) && !defined(PUBLISHER)
runningServer = UA_FALSE;
#endif
UA_free(threadArgumentsSubscriber);
return (void*)NULL;
}
Expand Down Expand Up @@ -1102,7 +1113,11 @@ void *userApplicationPubSub(void *arg) {
nextnanosleeptimeUserApplication.tv_nsec = threadBaseTime.tv_nsec + (__syscall_slong_t)(cycleTimeInMsec * MILLI_SECONDS * userAppWakeupPercentage);
nanoSecondFieldConversion(&nextnanosleeptimeUserApplication);

#if defined(PUBLISHER) && defined(SUBSCRIBER)
while (*runningSub || *runningPub) {
#else
while (*runningSub) {
#endif
/* The User application threads wakes up at the configured userApp wake up percentage (30%) of each cycle */
clock_nanosleep(CLOCKID, TIMER_ABSTIME, &nextnanosleeptimeUserApplication, NULL);
#if defined(SUBSCRIBER)
Expand Down Expand Up @@ -1507,13 +1522,23 @@ int main(int argc, char **argv) {
UA_ServerConfig_setMinimal(config, PORT_NUMBER, NULL);

#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
#if defined(PUBLISHER) && defined(SUBSCRIBER)
/* Instantiate the PubSub SecurityPolicy */
config->pubSubConfig.securityPolicies = (UA_PubSubSecurityPolicy*)
UA_calloc(2, sizeof(UA_PubSubSecurityPolicy));
config->pubSubConfig.securityPoliciesSize = 2;
UA_PubSubSecurityPolicy_Aes128Ctr(&config->pubSubConfig.securityPolicies[0],
#else
config->pubSubConfig.securityPolicies = (UA_PubSubSecurityPolicy*)
UA_malloc(sizeof(UA_PubSubSecurityPolicy));
config->pubSubConfig.securityPoliciesSize = 1;
#endif
#endif

#if defined(UA_ENABLE_PUBSUB_ENCRYPTION) && defined(PUBLISHER)
UA_PubSubSecurityPolicy_Aes128Ctr(&config->pubSubConfig.securityPolicies[1],
&config->logger);
#endif

#if defined(PUBLISHER)
UA_NetworkAddressUrlDataType networkAddressUrlPub;
#endif
Expand Down Expand Up @@ -1562,8 +1587,9 @@ if (enableCsvLog)
addDataSetWriter(server);
UA_Server_freezeWriterGroupConfiguration(server, writerGroupIdent);
#endif
#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
UA_PubSubSecurityPolicy_Aes128Ctr(&config->pubSubConfig.securityPolicies[1],

#if defined(UA_ENABLE_PUBSUB_ENCRYPTION) && defined(SUBSCRIBER)
UA_PubSubSecurityPolicy_Aes128Ctr(&config->pubSubConfig.securityPolicies[0],
&config->logger);
#endif
#if defined (PUBLISHER) && defined(SUBSCRIBER)
Expand Down Expand Up @@ -1594,6 +1620,7 @@ if (enableCsvLog)
#if defined(SUBSCRIBER)
UA_Server_unfreezeReaderGroupConfiguration(server, readerGroupIdentifier);
#endif

#if defined(PUBLISHER) || defined(SUBSCRIBER)
returnValue = pthread_join(userThreadID, NULL);
if (returnValue != 0)
Expand Down
26 changes: 25 additions & 1 deletion examples/pubsub_realtime/pubsub_TSN_publisher.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,14 +160,18 @@ static UA_Double userAppWakeupPercentage = 0.3;
#define UA_AES128CTR_KEY_LENGTH 16
#define UA_AES128CTR_KEYNONCE_LENGTH 4

#if defined(PUBLISHER)
UA_Byte signingKeyPub[UA_AES128CTR_SIGNING_KEY_LENGTH] = {0};
UA_Byte encryptingKeyPub[UA_AES128CTR_KEY_LENGTH] = {0};
UA_Byte keyNoncePub[UA_AES128CTR_KEYNONCE_LENGTH] = {0};
#endif

#if defined(SUBSCRIBER)
UA_Byte signingKeySub[UA_AES128CTR_SIGNING_KEY_LENGTH] = {0};
UA_Byte encryptingKeySub[UA_AES128CTR_KEY_LENGTH] = {0};
UA_Byte keyNonceSub[UA_AES128CTR_KEYNONCE_LENGTH] = {0};
#endif
#endif

/* If the Hardcoded publisher/subscriber MAC addresses need to be changed,
* change PUBLISHING_MAC_ADDRESS and SUBSCRIBING_MAC_ADDRESS
Expand Down Expand Up @@ -1017,6 +1021,9 @@ void *publisherETF(void *arg) {
nanoSecondFieldConversion(&nextnanosleeptime);
}

#if defined(PUBLISHER) && !defined(SUBSCRIBER)
runningServer = UA_FALSE;
#endif
UA_free(threadArgumentsPublisher);
return (void*)NULL;
}
Expand Down Expand Up @@ -1113,7 +1120,12 @@ void *userApplicationPubSub(void *arg) {
{
*repeatedCounterData[iterator] = repeatedCounterValue;
}

#if defined(PUBLISHER) && defined(SUBSCRIBER)
while (*runningPub || *runningSub) {
#else
while (*runningPub) {
#endif
/* The User application threads wakes up at the configured userApp wake up percentage (30%) of each cycle */
clock_nanosleep(CLOCKID, TIMER_ABSTIME, &nextnanosleeptimeUserApplication, NULL);
#if defined(PUBLISHER)
Expand Down Expand Up @@ -1604,10 +1616,19 @@ int main(int argc, char **argv) {

UA_ServerConfig_setMinimal(config, PORT_NUMBER, NULL);
#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
#if defined(PUBLISHER) && defined(SUBSCRIBER)
/* Instantiate the PubSub SecurityPolicy */
config->pubSubConfig.securityPolicies = (UA_PubSubSecurityPolicy*)
UA_calloc(2, sizeof(UA_PubSubSecurityPolicy));
config->pubSubConfig.securityPoliciesSize = 2;
#else
config->pubSubConfig.securityPolicies = (UA_PubSubSecurityPolicy*)
UA_malloc(sizeof(UA_PubSubSecurityPolicy));
config->pubSubConfig.securityPoliciesSize = 1;
#endif
#endif

#if defined(UA_ENABLE_PUBSUB_ENCRYPTION) && defined(PUBLISHER)
UA_PubSubSecurityPolicy_Aes128Ctr(&config->pubSubConfig.securityPolicies[0],
&config->logger);
#endif
Expand Down Expand Up @@ -1659,10 +1680,12 @@ if (enableCsvLog) {
addDataSetWriter(server);
UA_Server_freezeWriterGroupConfiguration(server, writerGroupIdent);
#endif
#ifdef UA_ENABLE_PUBSUB_ENCRYPTION

#if defined(UA_ENABLE_PUBSUB_ENCRYPTION) && defined(SUBSCRIBER)
UA_PubSubSecurityPolicy_Aes128Ctr(&config->pubSubConfig.securityPolicies[1],
&config->logger);
#endif

#if defined (PUBLISHER) && defined(SUBSCRIBER)
UA_ServerConfig_addPubSubTransportLayer(config, UA_PubSubTransportLayerEthernet());
#endif
Expand Down Expand Up @@ -1733,6 +1756,7 @@ if (enableCsvLog) {
UA_Server_delete(server);
UA_free(serverConfig);
#endif

#if defined(PUBLISHER)
UA_free(runningPub);
UA_free(pubCounterData);
Expand Down
5 changes: 1 addition & 4 deletions plugins/ua_pubsub_ethernet.c
Original file line number Diff line number Diff line change
Expand Up @@ -1243,7 +1243,7 @@ UA_PubSubChannelEthernet_receive(UA_PubSubChannel *channel,
* VLAN header size is stripped before it is recieved
* so the packet length is less than 60bytes */

messageLength = messageLength + ((size_t)dataLen - sizeof(struct ether_header));
messageLength = ((size_t)dataLen - sizeof(struct ether_header));
buffer.length = messageLength;

retval = receiveCallback(channel, receiveCallbackContext, &buffer);
Expand All @@ -1264,9 +1264,6 @@ UA_PubSubChannelEthernet_receive(UA_PubSubChannel *channel,
/* The recvmsg API with MSG_DONTWAIT flag will not wait for the next packet */
receiveFlags = MSG_DONTWAIT;

#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
break;//ToDO: Multiple Receive handling for PubsubEncryption need to be done
#endif
} while(true); /* 1518 bytes is the maximum size of ethernet packet
* where 18 bytes used for header size, 4 bytes of LLC
* so remaining length is 1496 */
Expand Down
4 changes: 1 addition & 3 deletions plugins/ua_pubsub_udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -631,9 +631,7 @@ UA_PubSubChannelUDPMC_receive(UA_PubSubChannel *channel,
UA_DateTime newTimeoutValue = remainingTimeoutValue - receiveDuration;
timeoutValue.tv_sec = (long int)(newTimeoutValue / UA_DATETIME_SEC);
timeoutValue.tv_usec = (long int)((newTimeoutValue % UA_DATETIME_SEC) * 100);
#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
break;//ToDO: Multiple Receive handling for PubsubEncryption need to be done
#endif

} while(true); /* TODO:Need to handle for jumbo frames*/
/* 1518 bytes is the maximum size of ethernet packet
* where 18 bytes used for header size, 28 bytes of header
Expand Down
1 change: 1 addition & 0 deletions src/pubsub/ua_pubsub.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ UA_DataSetReader_handleMessageReceiveTimeout(UA_Server *server,

UA_StatusCode
UA_DataSetReader_generateNetworkMessage(UA_PubSubConnection *pubSubConnection,
UA_ReaderGroup *readerGroup,
UA_DataSetReader *dataSetReader,
UA_DataSetMessage *dsm, UA_UInt16 *writerId,
UA_Byte dsmCount, UA_NetworkMessage *nm);
Expand Down
9 changes: 6 additions & 3 deletions src/pubsub/ua_pubsub_networkmessage.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ const UA_Byte DS_MESSAGEHEADER_PICOSECONDS_INCLUDED_MASK = 32;
const UA_Byte NM_SHIFT_LEN = 2;
const UA_Byte DS_MH_SHIFT_LEN = 1;

/* Static memory allocation for the message nonce */
#define MESSAGE_NONCE_LENGTH 8
static UA_Byte MessageNonceGenerated[MESSAGE_NONCE_LENGTH];

static UA_Boolean UA_NetworkMessage_ExtendedFlags1Enabled(const UA_NetworkMessage* src);
static UA_Boolean UA_NetworkMessage_ExtendedFlags2Enabled(const UA_NetworkMessage* src);
static UA_Boolean UA_DataSetMessageHeader_DataSetFlags2Enabled(const UA_DataSetMessageHeader* src);
Expand Down Expand Up @@ -762,7 +766,8 @@ UA_SecurityHeader_decodeBinary(const UA_ByteString *src, size_t *offset,
// MessageNonce
if(nonceLength > 0) {
//TODO: check for memory leaks
rv = UA_ByteString_allocBuffer(&dst->securityHeader.messageNonce, nonceLength);
dst->securityHeader.messageNonce.length = MESSAGE_NONCE_LENGTH;
dst->securityHeader.messageNonce.data = MessageNonceGenerated;
UA_CHECK_STATUS(rv, return rv);
for (UA_Byte i = 0; i < nonceLength; i++) {
rv = UA_Byte_decodeBinary(src, offset,
Expand Down Expand Up @@ -1095,8 +1100,6 @@ UA_NetworkMessage_clear(UA_NetworkMessage* p) {
if(p->promotedFieldsEnabled)
UA_Array_delete(p->promotedFields, p->promotedFieldsSize, &UA_TYPES[UA_TYPES_VARIANT]);

UA_ByteString_clear(&p->securityHeader.messageNonce);

if(p->networkMessageType == UA_NETWORKMESSAGE_DATASET) {
if(p->payloadHeaderEnabled) {
if(p->payloadHeader.dataSetPayloadHeader.dataSetWriterIds != NULL) {
Expand Down
55 changes: 29 additions & 26 deletions src/pubsub/ua_pubsub_reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@
/* This functionality of this API will be used in future to create mirror Variables - TODO */
/* #define UA_MAX_SIZENAME 64 */ /* Max size of Qualified Name of Subscribed Variable */

/* Static memory allocation for the message nonce */
#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
#define MESSAGE_NONCE_LENGTH 8
static UA_Byte MessageNonceGenerated[MESSAGE_NONCE_LENGTH];
#endif

/* Clear DataSetReader */
static void
UA_DataSetReader_clear(UA_Server *server, UA_DataSetReader *dataSetReader);
Expand Down Expand Up @@ -210,10 +216,9 @@ UA_DataSetReader_generateDataSetMessage(UA_Server *server,
}

UA_StatusCode
UA_DataSetReader_generateNetworkMessage(UA_PubSubConnection *pubSubConnection,
UA_DataSetReader *dataSetReader,
UA_DataSetMessage *dsm, UA_UInt16 *writerId,
UA_Byte dsmCount, UA_NetworkMessage *nm) {
UA_DataSetReader_generateNetworkMessage(UA_PubSubConnection *pubSubConnection, UA_ReaderGroup *readerGroup,
UA_DataSetReader *dataSetReader, UA_DataSetMessage *dsm, UA_UInt16 *writerId, UA_Byte dsmCount,
UA_NetworkMessage *nm) {
UA_ExtensionObject *settings = &dataSetReader->config.messageSettings;
if(settings->content.decoded.type != &UA_TYPES[UA_TYPES_UADPDATASETREADERMESSAGEDATATYPE])
return UA_STATUSCODE_BADNOTSUPPORTED;
Expand Down Expand Up @@ -252,9 +257,8 @@ UA_DataSetReader_generateNetworkMessage(UA_PubSubConnection *pubSubConnection,
nm->securityHeader.securityTokenId = readerGroup->securityTokenId;

/* Generate the MessageNonce */
UA_ByteString_allocBuffer(&nm->securityHeader.messageNonce, 8);
if(nm->securityHeader.messageNonce.length == 0)
return UA_STATUSCODE_BADOUTOFMEMORY;
nm->securityHeader.messageNonce.length = MESSAGE_NONCE_LENGTH;
nm->securityHeader.messageNonce.data = MessageNonceGenerated;

nm->securityHeader.messageNonce.length = 4; /* Generate 4 random bytes */
UA_StatusCode rv = readerGroup->config.securityPolicy->symmetricModule.
Expand Down Expand Up @@ -1384,26 +1388,25 @@ decodeAndProcessNetworkMessageRT(UA_Server *server, UA_ReaderGroup *readerGroup,
UA_NetworkMessage *nm = dataSetReader->bufferedMessage.nm;

#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
if(readerGroup->config.securityMode > UA_MESSAGESECURITYMODE_NONE) {
UA_NetworkMessage currentNetworkMessage;
memset(&currentNetworkMessage, 0, sizeof(UA_NetworkMessage));
UA_StatusCode rv;
size_t payLoadPosition = 0;
rv = UA_NetworkMessage_decodeHeaders(
buffer, &payLoadPosition, &currentNetworkMessage);

UA_CHECK_STATUS_ERROR(rv, return rv, &server->config.logger, UA_LOGCATEGORY_SERVER,
"PubSub receive. decoding headers failed");
rv = verifyAndDecryptNetworkMessage(&server->config.logger,
buffer,
&payLoadPosition,
&currentNetworkMessage,
readerGroup);
UA_CHECK_STATUS_WARN(rv, return rv, &server->config.logger, UA_LOGCATEGORY_SERVER,
"Subscribe failed. verify and decrypt network message failed.");
UA_NetworkMessage_clear(&currentNetworkMessage);
}
UA_NetworkMessage currentNetworkMessage;
memset(&currentNetworkMessage, 0, sizeof(UA_NetworkMessage));
UA_StatusCode rv;
size_t payLoadPosition = 0;
rv = UA_NetworkMessage_decodeHeaders(
buffer, &payLoadPosition, &currentNetworkMessage);

UA_CHECK_STATUS_ERROR(rv, return rv, &server->config.logger, UA_LOGCATEGORY_SERVER,
"PubSub receive. decoding headers failed");
rv = verifyAndDecryptNetworkMessage(&server->config.logger,
buffer,
&payLoadPosition,
&currentNetworkMessage,
readerGroup);
UA_CHECK_STATUS_WARN(rv, return rv, &server->config.logger, UA_LOGCATEGORY_SERVER,
"Subscribe failed. verify and decrypt network message failed.");
UA_NetworkMessage_clear(&currentNetworkMessage);
#endif

/* Decode only the necessary offset and update the networkMessage */
UA_StatusCode res =
UA_NetworkMessage_updateBufferedNwMessage(&dataSetReader->bufferedMessage,
Expand Down
2 changes: 1 addition & 1 deletion src/pubsub/ua_pubsub_readergroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ UA_Server_freezeReaderGroupConfiguration(UA_Server *server,
return UA_STATUSCODE_BADOUTOFMEMORY;
}

res = UA_DataSetReader_generateNetworkMessage(pubSubConnection, dataSetReader, dsm,
res = UA_DataSetReader_generateNetworkMessage(pubSubConnection, rg, dataSetReader, dsm,
dsWriterIds, 1, networkMessage);
if(res != UA_STATUSCODE_GOOD) {
UA_free(networkMessage->payload.dataSetPayload.sizes);
Expand Down
6 changes: 0 additions & 6 deletions src/pubsub/ua_pubsub_writer.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,6 @@
/* Forward declaration */
static void
UA_DataSetField_clear(UA_DataSetField *field);
#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
static UA_StatusCode
encryptAndSign(UA_WriterGroup *wg, const UA_NetworkMessage *nm,
UA_Byte *signStart, UA_Byte *encryptStart,
UA_Byte *msgEnd);
#endif

/**********************************************/
/* Connection */
Expand Down

0 comments on commit fbc0253

Please sign in to comment.