Sfoglia il codice sorgente

fixed a bug in opensecurechannel
better securetoken handling (we now may have 2 active tokens)
fixes #278

Stasik0 9 anni fa
parent
commit
dd9699d7da

+ 30 - 13
src/server/ua_securechannel_manager.c

@@ -31,8 +31,15 @@ void UA_SecureChannelManager_cleanupTimedOut(UA_SecureChannelManager *cm, UA_Dat
             (UA_DateTime)entry->channel.securityToken.revisedLifetime*10000 > now &&
             entry->channel.connection) {
             entry = LIST_NEXT(entry, pointers);
+        }else if(entry->channel.nextSecurityToken.tokenId > 0 &&
+                 entry->channel.nextSecurityToken.createdAt +
+                (UA_DateTime)entry->channel.nextSecurityToken.revisedLifetime*10000 > now &&
+                entry->channel.connection){
+            UA_SecureChannel_revolveTokens(&entry->channel);
+            entry = LIST_NEXT(entry, pointers);
         }
         else {
+            printf("kill\n");
             channel_list_entry *next = LIST_NEXT(entry, pointers);
             LIST_REMOVE(entry, pointers);
             UA_SecureChannel_deleteMembersCleanup(&entry->channel);
@@ -100,22 +107,32 @@ UA_StatusCode UA_SecureChannelManager_renew(UA_SecureChannelManager *cm, UA_Conn
     if(channel == UA_NULL)
         return UA_STATUSCODE_BADINTERNALERROR;
 
-    channel->securityToken.tokenId         = cm->lastTokenId++;
-    channel->securityToken.createdAt       = UA_DateTime_now(); // todo: is wanted?
-    channel->securityToken.revisedLifetime = (request->requestedLifetime > cm->maxChannelLifetime) ?
-                                             cm->maxChannelLifetime : request->requestedLifetime;
-    //FIXME: pragmatic workaround to get clients requesting lifetime of 0 working
-    if(channel->securityToken.revisedLifetime == 0){
-        channel->securityToken.revisedLifetime = cm->maxChannelLifetime;
-        //FIXME: I'd log it, but there is no pointer to the logger
-        // printf("Warning: client requests token lifetime of 0 in renewing SecureChannel setting it to %llu\n", cm->maxChannelLifetime);
+    printf("new token issued\n");
+
+    //if no new security token is already issued
+    if(channel->nextSecurityToken.tokenId == 0){
+        channel->nextSecurityToken.channelId       = channel->securityToken.channelId;
+        //FIXME: UaExpert seems not to use new the new tokenid
+        channel->nextSecurityToken.tokenId         = cm->lastTokenId++;
+        //channel->nextSecurityToken.tokenId         = channel->securityToken.tokenId;
+        channel->nextSecurityToken.createdAt       = UA_DateTime_now();
+        channel->nextSecurityToken.revisedLifetime = (request->requestedLifetime > cm->maxChannelLifetime) ?
+                                                 cm->maxChannelLifetime : request->requestedLifetime;
+
+        //FIXME: pragmatic workaround to get clients requesting lifetime of 0 working
+        if(channel->nextSecurityToken.revisedLifetime == 0){
+            channel->nextSecurityToken.revisedLifetime = cm->maxChannelLifetime;
+            //FIXME: I'd log it, but there is no pointer to the logger
+            // printf("Warning: client requests token lifetime of 0 in renewing SecureChannel setting it to %llu\n", cm->maxChannelLifetime);
+        }
+
     }
+    if(channel->clientNonce.data)
+        UA_ByteString_deleteMembers(&channel->clientNonce);
+    UA_ByteString_copy(&request->clientNonce, &channel->clientNonce);
 
-    if(channel->serverNonce.data != UA_NULL)
-        UA_ByteString_deleteMembers(&channel->serverNonce);
-    UA_SecureChannel_generateNonce(&channel->serverNonce);
     UA_ByteString_copy(&channel->serverNonce, &response->serverNonce);
-    UA_ChannelSecurityToken_copy(&channel->securityToken, &response->securityToken);
+    UA_ChannelSecurityToken_copy(&channel->nextSecurityToken, &response->securityToken);
     return UA_STATUSCODE_GOOD;
 }
 

+ 1 - 1
src/server/ua_server.c

@@ -415,7 +415,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
 
 #define MAXCHANNELCOUNT 100
 #define STARTCHANNELID 1
-#define TOKENLIFETIME 600000 //this is in milliseconds
+#define TOKENLIFETIME 600000 //this is in milliseconds //600000 seems to be the minimal allowet time for UaExpert
 #define STARTTOKENID 1
     UA_SecureChannelManager_init(&server->secureChannelManager, MAXCHANNELCOUNT,
                                  TOKENLIFETIME, STARTCHANNELID, STARTTOKENID);

+ 21 - 6
src/server/ua_server_binary.c

@@ -6,8 +6,6 @@
 #include "ua_statuscodes.h"
 #include "ua_securechannel_manager.h"
 #include "ua_session_manager.h"
-#include "ua_nodeids.h"
-
 /** Max size of messages that are allocated on the stack */
 #define MAX_STACK_MESSAGE 65536
 
@@ -100,7 +98,11 @@ static void processOPN(UA_Connection *connection, UA_Server *server, const UA_By
     }
 
     /* send the response with an asymmetric security header */
-    seqHeader.sequenceNumber = channel->sequenceNumber;
+#ifndef UA_MULTITHREADING
+    seqHeader.sequenceNumber = ++channel->sequenceNumber;
+#else
+    seqHeader.sequenceNumber = uatomic_add_return(&channel->sequenceNumber, 1);
+#endif
 
     UA_SecureConversationMessageHeader respHeader;
     respHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_OPNF;
@@ -215,9 +217,20 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     UA_SequenceHeader sequenceHeader;
     retval = UA_UInt32_decodeBinary(msg, pos, &tokenId);
     retval |= UA_SequenceHeader_decodeBinary(msg, pos, &sequenceHeader);
-    if(retval != UA_STATUSCODE_GOOD)
+    if(retval != UA_STATUSCODE_GOOD || tokenId==0) //0 is invalid
         return;
 
+    if(clientChannel != &anonymousChannel){
+        if(tokenId!=clientChannel->securityToken.tokenId){
+            //is client using a newly issued token?
+            if(tokenId==clientChannel->nextSecurityToken.tokenId){ //tokenId is not 0
+                UA_SecureChannel_revolveTokens(clientChannel);
+            }else{
+                //FIXME: how to react to this, what do we have to return? Or just kill the channel
+            }
+        }
+    }
+
     /* Read the request type */
     UA_NodeId requestType;
     if(UA_NodeId_decodeBinary(msg, pos, &requestType) != UA_STATUSCODE_GOOD)
@@ -374,9 +387,11 @@ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection
             break;
         case UA_MESSAGETYPEANDFINAL_MSGF & 0xffffff:
 #ifndef EXTENSION_STATELESS
-            if(connection->state != UA_CONNECTION_ESTABLISHED)
+            if(connection->state != UA_CONNECTION_ESTABLISHED){
                 connection->close(connection);
-            else
+                UA_ByteString_deleteMembers(msg);
+                return;
+            }else
 #endif
                 processMSG(connection, server, msg, &pos);
             break;

+ 14 - 1
src/ua_securechannel.c

@@ -7,6 +7,7 @@
 void UA_SecureChannel_init(UA_SecureChannel *channel) {
     UA_MessageSecurityMode_init(&channel->securityMode);
     UA_ChannelSecurityToken_init(&channel->securityToken);
+    UA_ChannelSecurityToken_init(&channel->nextSecurityToken);
     UA_AsymmetricAlgorithmSecurityHeader_init(&channel->clientAsymAlgSettings);
     UA_AsymmetricAlgorithmSecurityHeader_init(&channel->serverAsymAlgSettings);
     UA_ByteString_init(&channel->clientNonce);
@@ -21,7 +22,8 @@ void UA_SecureChannel_deleteMembersCleanup(UA_SecureChannel *channel) {
     UA_ByteString_deleteMembers(&channel->serverNonce);
     UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&channel->clientAsymAlgSettings);
     UA_ByteString_deleteMembers(&channel->clientNonce);
-    UA_ChannelSecurityToken_deleteMembers(&channel->securityToken);
+    UA_ChannelSecurityToken_deleteMembers(&channel->securityToken); //FIXME: not really needed
+    UA_ChannelSecurityToken_deleteMembers(&channel->nextSecurityToken); //FIXME: not really needed
     UA_Connection *c = channel->connection;
     if(c) {
         UA_Connection_detachSecureChannel(c);
@@ -88,6 +90,17 @@ UA_Session * UA_SecureChannel_getSession(UA_SecureChannel *channel, UA_NodeId *t
     return se->session;
 }
 
+void UA_SecureChannel_revolveTokens(UA_SecureChannel *channel){
+    if(channel->nextSecurityToken.tokenId==0) //no security token issued
+        return;
+
+    printf("revolved\n");
+    //FIXME: not thread-safe
+    //swap tokens
+    memcpy(&channel->securityToken, &channel->nextSecurityToken, sizeof(UA_ChannelSecurityToken));
+    UA_ChannelSecurityToken_init(&channel->nextSecurityToken);
+}
+
 UA_StatusCode UA_SecureChannel_sendBinaryMessage(UA_SecureChannel *channel, UA_UInt32 requestId,
                                                   const void *content,
                                                   const UA_DataType *contentType) {

+ 2 - 0
src/ua_securechannel.h

@@ -23,6 +23,7 @@ struct SessionEntry {
 struct UA_SecureChannel {
     UA_MessageSecurityMode  securityMode;
     UA_ChannelSecurityToken securityToken; // the channelId is contained in the securityToken
+    UA_ChannelSecurityToken nextSecurityToken; // the channelId is contained in the securityToken
     UA_AsymmetricAlgorithmSecurityHeader clientAsymAlgSettings;
     UA_AsymmetricAlgorithmSecurityHeader serverAsymAlgSettings;
     UA_ByteString  clientNonce;
@@ -44,6 +45,7 @@ UA_Session * UA_SecureChannel_getSession(UA_SecureChannel *channel, UA_NodeId *t
 UA_StatusCode UA_SecureChannel_sendBinaryMessage(UA_SecureChannel *channel, UA_UInt32 requestId,
                                                   const void *content, const UA_DataType *contentType);
 
+void UA_SecureChannel_revolveTokens(UA_SecureChannel *channel);
 /** @} */
 
 #endif /* UA_SECURECHANNEL_H_ */