ua_securechannel.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. #include "ua_util.h"
  2. #include "ua_securechannel.h"
  3. #include "ua_statuscodes.h"
  4. #include "ua_types_encoding_binary.h"
  5. // max message size is 64k
  6. const UA_ConnectionConfig UA_ConnectionConfig_standard =
  7. {.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize = 65536,
  8. .maxMessageSize = 65536, .maxChunkCount = 1};
  9. UA_ByteString UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString received)
  10. {
  11. if(received.length == -1)
  12. return received;
  13. /* concat received to the incomplete message we have */
  14. UA_ByteString current;
  15. if(connection->incompleteMessage.length < 0)
  16. current = received;
  17. else {
  18. current.data = UA_realloc(connection->incompleteMessage.data,
  19. connection->incompleteMessage.length + received.length);
  20. if(!current.data) {
  21. /* not enough memory */
  22. UA_ByteString_deleteMembers(&connection->incompleteMessage);
  23. connection->incompleteMessage.length = -1;
  24. UA_ByteString_deleteMembers(&received);
  25. received.length = -1;
  26. return received;
  27. }
  28. UA_memcpy(current.data + connection->incompleteMessage.length, received.data, received.length);
  29. current.length = connection->incompleteMessage.length + received.length;
  30. UA_ByteString_deleteMembers(&received);
  31. UA_ByteString_init(&connection->incompleteMessage);
  32. }
  33. /* find the first non-complete message */
  34. size_t end_pos = 0; // the end of the last complete message
  35. while(current.length - end_pos >= 32) {
  36. if(!(current.data[0] == 'M' && current.data[1] == 'S' && current.data[2] == 'G') &&
  37. !(current.data[0] == 'O' && current.data[1] == 'P' && current.data[2] == 'N') &&
  38. !(current.data[0] == 'H' && current.data[1] == 'E' && current.data[2] == 'L') &&
  39. !(current.data[0] == 'A' && current.data[1] == 'C' && current.data[2] == 'K') &&
  40. !(current.data[0] == 'C' && current.data[1] == 'L' && current.data[2] == 'O')) {
  41. current.length = end_pos; // throw the remaining bytestring away
  42. break;
  43. }
  44. UA_Int32 length = 0;
  45. size_t pos = end_pos + 4;
  46. UA_StatusCode retval = UA_Int32_decodeBinary(&current, &pos, &length);
  47. if(retval != UA_STATUSCODE_GOOD || length < 32 ||
  48. length > (UA_Int32)connection->localConf.maxMessageSize) {
  49. current.length = end_pos; // throw the remaining bytestring away
  50. break;
  51. }
  52. if(length + (UA_Int32)end_pos > current.length)
  53. break; // the message is incomplete
  54. end_pos += length;
  55. }
  56. if(current.length == 0) { /* throw everything away */
  57. UA_String_deleteMembers(&current);
  58. current.length = -1;
  59. return current;
  60. }
  61. /* retain the incomplete message at the end */
  62. if(current.length - end_pos > 0) {
  63. connection->incompleteMessage.data = UA_malloc(current.length - end_pos);
  64. if(connection->incompleteMessage.data) {
  65. UA_memcpy(connection->incompleteMessage.data, &current.data[end_pos], current.length - end_pos);
  66. connection->incompleteMessage.length = current.length - end_pos;
  67. }
  68. }
  69. current.length = end_pos;
  70. return current;
  71. }
  72. void UA_SecureChannel_init(UA_SecureChannel *channel) {
  73. UA_MessageSecurityMode_init(&channel->securityMode);
  74. UA_ChannelSecurityToken_init(&channel->securityToken);
  75. UA_AsymmetricAlgorithmSecurityHeader_init(&channel->clientAsymAlgSettings);
  76. UA_AsymmetricAlgorithmSecurityHeader_init(&channel->serverAsymAlgSettings);
  77. UA_ByteString_init(&channel->clientNonce);
  78. UA_ByteString_init(&channel->serverNonce);
  79. channel->requestId = 0;
  80. channel->sequenceNumber = 0;
  81. channel->connection = UA_NULL;
  82. channel->session = UA_NULL;
  83. }
  84. void UA_SecureChannel_deleteMembers(UA_SecureChannel *channel) {
  85. UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&channel->serverAsymAlgSettings);
  86. UA_ByteString_deleteMembers(&channel->serverNonce);
  87. UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&channel->clientAsymAlgSettings);
  88. UA_ByteString_deleteMembers(&channel->clientNonce);
  89. UA_ChannelSecurityToken_deleteMembers(&channel->securityToken);
  90. }
  91. void UA_SecureChannel_delete(UA_SecureChannel *channel) {
  92. UA_SecureChannel_deleteMembers(channel);
  93. UA_free(channel);
  94. }
  95. UA_Boolean UA_SecureChannel_compare(UA_SecureChannel *sc1, UA_SecureChannel *sc2) {
  96. return (sc1->securityToken.channelId == sc2->securityToken.channelId);
  97. }
  98. //TODO implement real nonce generator - DUMMY function
  99. UA_StatusCode UA_SecureChannel_generateNonce(UA_ByteString *nonce) {
  100. if(!(nonce->data = UA_malloc(1)))
  101. return UA_STATUSCODE_BADOUTOFMEMORY;
  102. nonce->length = 1;
  103. nonce->data[0] = 'a';
  104. return UA_STATUSCODE_GOOD;
  105. }
  106. UA_StatusCode UA_SecureChannel_updateRequestId(UA_SecureChannel *channel, UA_UInt32 requestId) {
  107. //TODO review checking of request id
  108. if(channel->requestId+1 != requestId)
  109. return UA_STATUSCODE_BADINTERNALERROR;
  110. channel->requestId++;
  111. return UA_STATUSCODE_GOOD;
  112. }
  113. UA_StatusCode UA_SecureChannel_updateSequenceNumber(UA_SecureChannel *channel, UA_UInt32 sequenceNumber) {
  114. //TODO review checking of sequence
  115. if(channel->sequenceNumber+1 != sequenceNumber)
  116. return UA_STATUSCODE_BADINTERNALERROR;
  117. channel->sequenceNumber++;
  118. return UA_STATUSCODE_GOOD;
  119. }
  120. void UA_Connection_detachSecureChannel(UA_Connection *connection) {
  121. #ifdef UA_MULTITHREADING
  122. UA_SecureChannel *channel = connection->channel;
  123. if(channel)
  124. uatomic_cmpxchg(&channel->connection, connection, UA_NULL);
  125. uatomic_set(&connection->channel, UA_NULL);
  126. #else
  127. if(connection->channel)
  128. connection->channel->connection = UA_NULL;
  129. connection->channel = UA_NULL;
  130. #endif
  131. }
  132. void UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChannel *channel) {
  133. #ifdef UA_MULTITHREADING
  134. if(uatomic_cmpxchg(&channel->connection, UA_NULL, connection) == UA_NULL)
  135. uatomic_set(&connection->channel, channel);
  136. #else
  137. if(channel->connection != UA_NULL)
  138. return;
  139. channel->connection = connection;
  140. connection->channel = channel;
  141. #endif
  142. }