Browse Source

Merge pull request #1736 from open62541/merge_03_master

Merge 0.3 into master
Stefan Profanter 6 years ago
parent
commit
74b7578cd7

+ 42 - 26
plugins/ua_nodestore_default.c

@@ -79,28 +79,33 @@ higher_prime_index(UA_UInt32 n) {
     return low;
 }
 
-/* returns an empty slot or null if the nodeid exists */
+/* returns an empty slot or null if the nodeid exists or if no empty slot is found. */
 static UA_NodeMapEntry **
 findFreeSlot(const UA_NodeMap *ns, const UA_NodeId *nodeid) {
+    UA_NodeMapEntry **retval = NULL;
     UA_UInt32 h = UA_NodeId_hash(nodeid);
     UA_UInt32 size = ns->size;
-    UA_UInt32 idx = mod(h, size);
+    UA_UInt64 idx = mod(h, size); // use 64 bit container to avoid overflow
+    UA_UInt32 startIdx = (UA_UInt32)idx;
     UA_UInt32 hash2 = mod2(h, size);
+    UA_NodeMapEntry *entry = NULL;
 
-    while(true) {
-        UA_NodeMapEntry *e = ns->entries[idx];
-        if(e > UA_NODEMAP_TOMBSTONE &&
-           UA_NodeId_equal(&e->node.nodeId, nodeid))
+    do {
+        entry = ns->entries[(UA_UInt32)idx];
+        if(entry > UA_NODEMAP_TOMBSTONE &&
+           UA_NodeId_equal(&entry->node.nodeId, nodeid))
             return NULL;
-        if(ns->entries[idx] <= UA_NODEMAP_TOMBSTONE)
-            return &ns->entries[idx];
+        if(!retval && entry <= UA_NODEMAP_TOMBSTONE)
+            retval = &ns->entries[(UA_UInt32)idx];
         idx += hash2;
         if(idx >= size)
             idx -= size;
-    }
+    } while((UA_UInt32)idx != startIdx && entry);
 
-    /* NOTREACHED */
-    return NULL;
+    /* NULL is returned if there is no free slot (idx == startIdx).
+     * Otherwise the first free slot is returned after we are sure,
+     * that the node id cannot be found in the used hashmap (!entry). */
+    return retval;
 }
 
 /* The occupancy of the table after the call will be about 50% */
@@ -204,22 +209,24 @@ static UA_NodeMapEntry **
 findOccupiedSlot(const UA_NodeMap *ns, const UA_NodeId *nodeid) {
     UA_UInt32 h = UA_NodeId_hash(nodeid);
     UA_UInt32 size = ns->size;
-    UA_UInt32 idx = mod(h, size);
+    UA_UInt64 idx = mod(h, size); // use 64 bit container to avoid overflow
     UA_UInt32 hash2 = mod2(h, size);
-
-    while(true) {
-        UA_NodeMapEntry *e = ns->entries[idx];
-        if(!e)
-            return NULL;
-        if(e > UA_NODEMAP_TOMBSTONE &&
-           UA_NodeId_equal(&e->node.nodeId, nodeid))
-            return &ns->entries[idx];
+    UA_UInt32 startIdx = (UA_UInt32)idx;
+    UA_NodeMapEntry *entry = NULL;
+
+    do {
+        entry = ns->entries[(UA_UInt32)idx];
+        if(entry > UA_NODEMAP_TOMBSTONE &&
+           UA_NodeId_equal(&entry->node.nodeId, nodeid))
+            return &ns->entries[(UA_UInt32)idx];
         idx += hash2;
         if(idx >= size)
             idx -= size;
-    }
+    } while((UA_UInt32)idx != startIdx && entry);
 
-    /* NOTREACHED */
+    /* NULL is returned if there is no free slot (idx == startIdx)
+     * and the node id is not found or if the end of the used slots (!entry)
+     * is reached. */
     return NULL;
 }
 
@@ -335,19 +342,28 @@ UA_NodeMap_insertNode(void *context, UA_Node *node,
             node->nodeId.identifier.numeric == 0) {
         /* create a random nodeid */
         /* start at least with 50,000 to make sure we don not conflict with nodes from the spec */
+        /* if we find a conflict, we just try another identifier until we have tried all possible identifiers */
+        /* since the size is prime and we don't change the increase val, we will reach the starting id again */
         /* E.g. adding a nodeset will create children while there are still other nodes which need to be created */
-        /* Thus the node id's may collide */
-        UA_UInt32 identifier = 50000 + ns->count+1; // start value
+        /* Thus the node ids may collide */
         UA_UInt32 size = ns->size;
+        UA_UInt64 identifier = mod(50000 + size+1, size); // start value, use 64 bit container to avoid overflow
         UA_UInt32 increase = mod2(ns->count+1, size);
-        while(true) {
-            node->nodeId.identifier.numeric = identifier;
+        UA_UInt32 startId = (UA_UInt32)identifier; // mod ensures us that the id is a valid 32 bit
+
+        do {
+            node->nodeId.identifier.numeric = (UA_UInt32)identifier;
             slot = findFreeSlot(ns, &node->nodeId);
             if(slot)
                 break;
             identifier += increase;
             if(identifier >= size)
                 identifier -= size;
+        } while((UA_UInt32)identifier != startId);
+        
+        if (!slot) {
+            END_CRITSECT(ns);
+            return UA_STATUSCODE_BADOUTOFMEMORY;
         }
     } else {
         slot = findFreeSlot(ns, &node->nodeId);

+ 2 - 0
src/server/ua_server_ns0.c

@@ -495,6 +495,8 @@ readMonitoredItems(UA_Server *server, const UA_NodeId *sessionId, void *sessionC
     UA_Session *session = UA_SessionManager_getSessionById(&server->sessionManager, sessionId);
     if(!session)
         return UA_STATUSCODE_BADINTERNALERROR;
+    if (inputSize == 0 || !input[0].data)
+        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
     UA_UInt32 subscriptionId = *((UA_UInt32*)(input[0].data));
     UA_Subscription* subscription = UA_Session_getSubscriptionById(session, subscriptionId);
     if(!subscription)

+ 7 - 1
src/ua_securechannel.c

@@ -1,6 +1,6 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  *    Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
  *    Copyright 2014, 2016-2017 (c) Florian Palm
@@ -631,6 +631,9 @@ UA_MessageContext_begin(UA_MessageContext *mc, UA_SecureChannel *channel,
     if(!connection)
         return UA_STATUSCODE_BADINTERNALERROR;
 
+    if(messageType != UA_MESSAGETYPE_MSG && messageType != UA_MESSAGETYPE_CLO)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
     /* Create the chunking info structure */
     mc->channel = channel;
     mc->requestId = requestId;
@@ -687,6 +690,9 @@ UA_StatusCode
 UA_SecureChannel_sendSymmetricMessage(UA_SecureChannel *channel, UA_UInt32 requestId,
                                       UA_MessageType messageType, void *payload,
                                       const UA_DataType *payloadType) {
+    if(!channel || !payload || !payloadType)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
     if(channel->connection) {
         if(channel->connection->state == UA_CONNECTION_CLOSED)
             return UA_STATUSCODE_BADCONNECTIONCLOSED;

+ 110 - 0
tests/check_securechannel.c

@@ -27,6 +27,7 @@
 #define DEFAULT_SYM_ENCRYPTION_KEY_LENGTH 5
 #define DEFAULT_ASYM_REMOTE_SIGNATURE_SIZE 7
 #define DEFAULT_ASYM_LOCAL_SIGNATURE_SIZE 11
+#define DEFAULT_SYM_SIGNATURE_SIZE 13
 #define DEFAULT_ASYM_REMOTE_PLAINTEXT_BLOCKSIZE 256
 #define DEFAULT_ASYM_REMOTE_BLOCKSIZE 256
 
@@ -74,6 +75,7 @@ setup_key_sizes(void) {
     keySizes.sym_sig_keyLen = DEFAULT_SYM_SIGNING_KEY_LENGTH;
     keySizes.sym_enc_blockSize = DEFAULT_SYM_ENCRYPTION_BLOCK_SIZE;
     keySizes.sym_enc_keyLen = DEFAULT_SYM_ENCRYPTION_KEY_LENGTH;
+    keySizes.sym_sig_size = DEFAULT_SYM_SIGNATURE_SIZE;
 
     keySizes.asym_lcl_sig_size = DEFAULT_ASYM_LOCAL_SIGNATURE_SIZE;
     keySizes.asym_rmt_sig_size = DEFAULT_ASYM_REMOTE_SIGNATURE_SIZE;
@@ -386,6 +388,103 @@ START_TEST(Securechannel_sendAsymmetricOPNMessage_extraPaddingPresentWhenKeyLarg
         UA_OpenSecureChannelResponse_deleteMembers(&sentResponse);
     }END_TEST
 
+START_TEST(SecureChannel_sendSymmetricMessage)
+    {
+        // initialize dummy message
+        UA_ReadRequest dummyMessage;
+        UA_ReadRequest_init(&dummyMessage);
+        UA_DataType dummyType = UA_TYPES[UA_TYPES_READREQUEST];
+
+        UA_StatusCode retval = UA_SecureChannel_sendSymmetricMessage(&testChannel, 42, UA_MESSAGETYPE_MSG,
+                                                                     &dummyMessage, &dummyType);
+        ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Expected success");
+        // TODO: expand test
+    }
+END_TEST
+
+START_TEST(SecureChannel_sendSymmetricMessage_modeNone)
+    {
+        // initialize dummy message
+        UA_ReadRequest dummyMessage;
+        UA_ReadRequest_init(&dummyMessage);
+        UA_DataType dummyType = UA_TYPES[UA_TYPES_READREQUEST];
+
+        testChannel.securityMode = UA_MESSAGESECURITYMODE_NONE;
+
+        UA_StatusCode retval = UA_SecureChannel_sendSymmetricMessage(&testChannel, 42, UA_MESSAGETYPE_MSG,
+                                                                     &dummyMessage, &dummyType);
+        ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Expected success");
+        ck_assert_msg(!fCalled.sym_sign, "Expected message to not have been signed");
+        ck_assert_msg(!fCalled.sym_enc, "Expected message to not have been encrypted");
+    }
+END_TEST
+
+
+START_TEST(SecureChannel_sendSymmetricMessage_modeSign)
+    {
+        // initialize dummy message
+        UA_ReadRequest dummyMessage;
+        UA_ReadRequest_init(&dummyMessage);
+        UA_DataType dummyType = UA_TYPES[UA_TYPES_READREQUEST];
+
+        testChannel.securityMode = UA_MESSAGESECURITYMODE_SIGN;
+
+        UA_StatusCode retval = UA_SecureChannel_sendSymmetricMessage(&testChannel, 42, UA_MESSAGETYPE_MSG,
+                                                                     &dummyMessage, &dummyType);
+        ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Expected success");
+        ck_assert_msg(fCalled.sym_sign, "Expected message to have been signed");
+        ck_assert_msg(!fCalled.sym_enc, "Expected message to not have been encrypted");
+    }
+END_TEST
+
+START_TEST(SecureChannel_sendSymmetricMessage_modeSignAndEncrypt)
+    {
+        // initialize dummy message
+        UA_ReadRequest dummyMessage;
+        UA_ReadRequest_init(&dummyMessage);
+        UA_DataType dummyType = UA_TYPES[UA_TYPES_READREQUEST];
+
+        testChannel.securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT;
+
+        UA_StatusCode retval = UA_SecureChannel_sendSymmetricMessage(&testChannel, 42, UA_MESSAGETYPE_MSG,
+                                                                     &dummyMessage, &dummyType);
+        ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Expected success");
+        ck_assert_msg(fCalled.sym_sign, "Expected message to have been signed");
+        ck_assert_msg(fCalled.sym_enc, "Expected message to have been encrypted");
+    }
+END_TEST
+
+START_TEST(SecureChannel_sendSymmetricMessage_invalidParameters)
+    {
+        // initialize dummy message
+        UA_ReadRequest dummyMessage;
+        UA_ReadRequest_init(&dummyMessage);
+        UA_DataType dummyType = UA_TYPES[UA_TYPES_READREQUEST];
+
+        UA_StatusCode retval = UA_SecureChannel_sendSymmetricMessage(NULL, 42, UA_MESSAGETYPE_MSG,
+                                                                     &dummyMessage, &dummyType);
+        ck_assert_msg(retval != UA_STATUSCODE_GOOD, "Expected failure");
+
+        retval = UA_SecureChannel_sendSymmetricMessage(&testChannel, 42, UA_MESSAGETYPE_HEL, &dummyMessage, &dummyType);
+        ck_assert_msg(retval != UA_STATUSCODE_GOOD, "Expected failure");
+
+        retval = UA_SecureChannel_sendSymmetricMessage(&testChannel, 42, UA_MESSAGETYPE_ACK, &dummyMessage, &dummyType);
+        ck_assert_msg(retval != UA_STATUSCODE_GOOD, "Expected failure");
+
+        retval = UA_SecureChannel_sendSymmetricMessage(&testChannel, 42, UA_MESSAGETYPE_ERR, &dummyMessage, &dummyType);
+        ck_assert_msg(retval != UA_STATUSCODE_GOOD, "Expected failure");
+
+        retval = UA_SecureChannel_sendSymmetricMessage(&testChannel, 42, UA_MESSAGETYPE_OPN, &dummyMessage, &dummyType);
+        ck_assert_msg(retval != UA_STATUSCODE_GOOD, "Expected failure");
+
+        retval = UA_SecureChannel_sendSymmetricMessage(&testChannel, 42, UA_MESSAGETYPE_MSG, NULL, &dummyType);
+        ck_assert_msg(retval != UA_STATUSCODE_GOOD, "Expected failure");
+
+        retval = UA_SecureChannel_sendSymmetricMessage(&testChannel, 42, UA_MESSAGETYPE_MSG, &dummyMessage, NULL);
+        ck_assert_msg(retval != UA_STATUSCODE_GOOD, "Expected failure");
+    }
+END_TEST
+
 static Suite *
 testSuite_SecureChannel(void) {
     Suite *s = suite_create("SecureChannel");
@@ -425,6 +524,17 @@ testSuite_SecureChannel(void) {
                    Securechannel_sendAsymmetricOPNMessage_extraPaddingPresentWhenKeyLargerThan2048Bits);
     suite_add_tcase(s, tc_sendAsymmetricOPNMessage);
 
+    TCase *tc_sendSymmetricMessage = tcase_create("Test sendSymmetricMessage function");
+    tcase_add_checked_fixture(tc_sendSymmetricMessage, setup_funcs_called, teardown_funcs_called);
+    tcase_add_checked_fixture(tc_sendSymmetricMessage, setup_key_sizes, teardown_key_sizes);
+    tcase_add_checked_fixture(tc_sendSymmetricMessage, setup_secureChannel, teardown_secureChannel);
+    tcase_add_test(tc_sendSymmetricMessage, SecureChannel_sendSymmetricMessage);
+    tcase_add_test(tc_sendSymmetricMessage, SecureChannel_sendSymmetricMessage_invalidParameters);
+    tcase_add_test(tc_sendSymmetricMessage, SecureChannel_sendSymmetricMessage_modeNone);
+    tcase_add_test(tc_sendSymmetricMessage, SecureChannel_sendSymmetricMessage_modeSign);
+    tcase_add_test(tc_sendSymmetricMessage, SecureChannel_sendSymmetricMessage_modeSignAndEncrypt);
+    suite_add_tcase(s, tc_sendSymmetricMessage);
+
     return s;
 }
 

+ 2 - 2
tests/testing-plugins/testing_policy.c

@@ -101,7 +101,7 @@ sym_getLocalSignatureSize_testing(const UA_SecurityPolicy *securityPolicy,
                                   const void *channelContext) {
     ck_assert(securityPolicy != NULL);
     ck_assert(channelContext != NULL);
-    return 0;
+    return keySizes->sym_sig_size;
 }
 
 static size_t
@@ -109,7 +109,7 @@ sym_getRemoteSignatureSize_testing(const UA_SecurityPolicy *securityPolicy,
                                    const void *channelContext) {
     ck_assert(securityPolicy != NULL);
     ck_assert(channelContext != NULL);
-    return 0;
+    return keySizes->sym_sig_size;
 }
 
 static size_t

+ 1 - 0
tests/testing-plugins/testing_policy.h

@@ -43,6 +43,7 @@ typedef struct funcs_called {
 typedef struct key_sizes {
     size_t sym_enc_blockSize;
     size_t sym_sig_keyLen;
+    size_t sym_sig_size;
     size_t sym_enc_keyLen;
 
     size_t asym_rmt_sig_size;