/* OPN messges to renew the channel are sent asynchronous */ static UA_StatusCode openSecureChannelAsync(UA_Client *client/*, UA_Boolean renew*/) { /* Check if sc is still valid */ /*if(renew && client->nextChannelRenewal - UA_DateTime_nowMonotonic () > 0) return UA_STATUSCODE_GOOD;*/ UA_Connection *conn = &client->connection; if(conn->state != UA_CONNECTION_ESTABLISHED) return UA_STATUSCODE_BADSERVERNOTCONNECTED; /* Prepare the OpenSecureChannelRequest */ UA_OpenSecureChannelRequest opnSecRq; UA_OpenSecureChannelRequest_init(&opnSecRq); opnSecRq.requestHeader.timestamp = UA_DateTime_now(); opnSecRq.requestHeader.authenticationToken = client->authenticationToken; /*if(renew) { opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_RENEW; UA_LOG_DEBUG(&client->config.logger, UA_LOGCATEGORY_SECURECHANNEL, "Requesting to renew the SecureChannel"); } else {*/ opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_ISSUE; UA_LOG_DEBUG(&client->config.logger, UA_LOGCATEGORY_SECURECHANNEL, "Requesting to open a SecureChannel"); //} opnSecRq.securityMode = client->channel.securityMode; opnSecRq.clientNonce = client->channel.localNonce; opnSecRq.requestedLifetime = client->config.secureChannelLifeTime; /* Prepare the entry for the linked list */ UA_UInt32 requestId = ++client->requestId; /*AsyncServiceCall *ac = NULL; if(renew) { ac = (AsyncServiceCall*)UA_malloc(sizeof(AsyncServiceCall)); if (!ac) return UA_STATUSCODE_BADOUTOFMEMORY; ac->callback = (UA_ClientAsyncServiceCallback) processDecodedOPNResponseAsync; ac->responseType = &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE]; ac->requestId = requestId; ac->userdata = NULL; }*/ /* Send the OPN message */ UA_StatusCode retval = UA_SecureChannel_sendAsymmetricOPNMessage ( &client->channel, requestId, &opnSecRq, &UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST]); client->connectStatus = retval; if(retval != UA_STATUSCODE_GOOD) { client->connectStatus = retval; UA_LOG_ERROR(&client->config.logger, UA_LOGCATEGORY_SECURECHANNEL, "Sending OPN message failed with error %s", UA_StatusCode_name(retval)); UA_Client_disconnect(client); //if(renew) // UA_free(ac); return retval; } UA_LOG_DEBUG(&client->config.logger, UA_LOGCATEGORY_SECURECHANNEL, "OPN message sent"); /* Store the entry for async processing and return */ /*if(renew) { LIST_INSERT_HEAD(&client->asyncServiceCalls, ac, pointers); return retval; }*/ return retval; }
static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew) { /* Check if sc is still valid */ if(renew && client->scExpiresAt - UA_DateTime_now() > client->config.timeToRenewSecureChannel * 10000) return UA_STATUSCODE_GOOD; UA_SecureConversationMessageHeader messageHeader; messageHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_OPNF; messageHeader.secureChannelId = 0; UA_SequenceHeader seqHeader; seqHeader.sequenceNumber = ++client->channel.sequenceNumber; seqHeader.requestId = ++client->requestId; UA_AsymmetricAlgorithmSecurityHeader asymHeader; UA_AsymmetricAlgorithmSecurityHeader_init(&asymHeader); asymHeader.securityPolicyUri = UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None"); /* id of opensecurechannelrequest */ UA_NodeId requestType = UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELREQUEST + UA_ENCODINGOFFSET_BINARY); UA_OpenSecureChannelRequest opnSecRq; UA_OpenSecureChannelRequest_init(&opnSecRq); opnSecRq.requestHeader.timestamp = UA_DateTime_now(); opnSecRq.requestHeader.authenticationToken = client->authenticationToken; opnSecRq.requestedLifetime = client->config.secureChannelLifeTime; if(renew) { opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_RENEW; UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "Requesting to renew the SecureChannel"); } else { opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_ISSUE; UA_ByteString_init(&client->channel.clientNonce); UA_ByteString_copy(&client->channel.clientNonce, &opnSecRq.clientNonce); opnSecRq.securityMode = UA_MESSAGESECURITYMODE_NONE; UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "Requesting to open a SecureChannel"); } UA_ByteString message; UA_Connection *c = &client->connection; UA_StatusCode retval = c->getSendBuffer(c, c->remoteConf.recvBufferSize, &message); if(retval != UA_STATUSCODE_GOOD) { UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); UA_OpenSecureChannelRequest_deleteMembers(&opnSecRq); return retval; } size_t offset = 12; retval = UA_AsymmetricAlgorithmSecurityHeader_encodeBinary(&asymHeader, &message, &offset); retval |= UA_SequenceHeader_encodeBinary(&seqHeader, &message, &offset); retval |= UA_NodeId_encodeBinary(&requestType, &message, &offset); retval |= UA_OpenSecureChannelRequest_encodeBinary(&opnSecRq, &message, &offset); messageHeader.messageHeader.messageSize = offset; offset = 0; retval |= UA_SecureConversationMessageHeader_encodeBinary(&messageHeader, &message, &offset); UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); UA_OpenSecureChannelRequest_deleteMembers(&opnSecRq); if(retval != UA_STATUSCODE_GOOD) { client->connection.releaseSendBuffer(&client->connection, &message); return retval; } message.length = messageHeader.messageHeader.messageSize; retval = client->connection.send(&client->connection, &message); if(retval != UA_STATUSCODE_GOOD) return retval; UA_ByteString reply; UA_ByteString_init(&reply); do { retval = client->connection.recv(&client->connection, &reply, client->config.timeout); if(retval != UA_STATUSCODE_GOOD) { UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "Receiving OpenSecureChannelResponse failed"); return retval; } } while(!reply.data); offset = 0; UA_SecureConversationMessageHeader_decodeBinary(&reply, &offset, &messageHeader); UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(&reply, &offset, &asymHeader); UA_SequenceHeader_decodeBinary(&reply, &offset, &seqHeader); UA_NodeId_decodeBinary(&reply, &offset, &requestType); UA_NodeId expectedRequest = UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELRESPONSE + UA_ENCODINGOFFSET_BINARY); if(!UA_NodeId_equal(&requestType, &expectedRequest)) { UA_ByteString_deleteMembers(&reply); UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); UA_NodeId_deleteMembers(&requestType); UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_CLIENT, "Reply answers the wrong request. Expected OpenSecureChannelResponse."); return UA_STATUSCODE_BADINTERNALERROR; } UA_OpenSecureChannelResponse response; UA_OpenSecureChannelResponse_init(&response); retval = UA_OpenSecureChannelResponse_decodeBinary(&reply, &offset, &response); if(retval != UA_STATUSCODE_GOOD) { UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "Decoding OpenSecureChannelResponse failed"); UA_ByteString_deleteMembers(&reply); UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); UA_OpenSecureChannelResponse_init(&response); response.responseHeader.serviceResult = retval; return retval; } client->scExpiresAt = UA_DateTime_now() + response.securityToken.revisedLifetime * 10000; UA_ByteString_deleteMembers(&reply); retval = response.responseHeader.serviceResult; if(retval != UA_STATUSCODE_GOOD) UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "SecureChannel could not be opened / renewed"); else if(!renew) { UA_ChannelSecurityToken_copy(&response.securityToken, &client->channel.securityToken); /* if the handshake is repeated, replace the old nonce */ UA_ByteString_deleteMembers(&client->channel.serverNonce); UA_ByteString_copy(&response.serverNonce, &client->channel.serverNonce); UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "SecureChannel opened"); } else UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "SecureChannel renewed"); UA_OpenSecureChannelResponse_deleteMembers(&response); UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); return retval; }
static int sendOpenSecureChannel(UA_Int32 sock) { UA_TcpMessageHeader msghdr; msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_OPNF; UA_UInt32 secureChannelId = 0; UA_String securityPolicy; UA_String_copycstring("http://opcfoundation.org/UA/SecurityPolicy#None", &securityPolicy); UA_String senderCert; senderCert.data = UA_NULL; senderCert.length = -1; UA_String receiverCertThumb; receiverCertThumb.data = UA_NULL; receiverCertThumb.length = -1; UA_UInt32 sequenceNumber = 51; UA_UInt32 requestId = 1; UA_NodeId type; type.identifier.numeric = 446; // id of opensecurechannelrequest type.identifierType = UA_NODEIDTYPE_NUMERIC; type.namespaceIndex = 0; UA_OpenSecureChannelRequest opnSecRq; UA_OpenSecureChannelRequest_init(&opnSecRq); opnSecRq.requestHeader.timestamp = UA_DateTime_now(); UA_ByteString_newMembers(&opnSecRq.clientNonce, 1); opnSecRq.clientNonce.data[0] = 0; opnSecRq.clientProtocolVersion = 0; opnSecRq.requestedLifetime = 30000; opnSecRq.securityMode = UA_MESSAGESECURITYMODE_NONE; opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_ISSUE; opnSecRq.requestHeader.authenticationToken.identifier.numeric = 10; opnSecRq.requestHeader.authenticationToken.identifierType = UA_NODEIDTYPE_NUMERIC; opnSecRq.requestHeader.authenticationToken.namespaceIndex = 10; msghdr.messageSize = 135; // todo: compute the message size from the actual content UA_ByteString message; UA_ByteString_newMembers(&message, 1000); size_t offset = 0; UA_TcpMessageHeader_encodeBinary(&msghdr, &message, &offset); UA_UInt32_encodeBinary(&secureChannelId, &message, &offset); UA_String_encodeBinary(&securityPolicy, &message, &offset); UA_String_encodeBinary(&senderCert, &message, &offset); UA_String_encodeBinary(&receiverCertThumb, &message, &offset); UA_UInt32_encodeBinary(&sequenceNumber, &message, &offset); UA_UInt32_encodeBinary(&requestId, &message, &offset); UA_NodeId_encodeBinary(&type, &message, &offset); UA_OpenSecureChannelRequest_encodeBinary(&opnSecRq, &message, &offset); UA_OpenSecureChannelRequest_deleteMembers(&opnSecRq); UA_String_deleteMembers(&securityPolicy); UA_Int32 sendret = send(sock, message.data, offset, 0); UA_ByteString_deleteMembers(&message); if (sendret < 0) { printf("send opensecurechannel failed"); return 1; } return 0; }