void UA_SecureChannel_init(UA_SecureChannel *channel) { UA_AsymmetricAlgorithmSecurityHeader_init(&channel->clientAsymAlgSettings); UA_AsymmetricAlgorithmSecurityHeader_init(&channel->serverAsymAlgSettings); UA_ByteString_init(&channel->clientNonce); UA_ByteString_init(&channel->serverNonce); channel->connection = UA_NULL; channel->session = UA_NULL; }
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; }