28 #ifdef SSL_SUPPORT_MBEDTLS 29 #define MBEDTLS_X509_CRT_PARSE_C 30 #include <mbedtls/entropy.h> 31 #include <mbedtls/ctr_drbg.h> 32 #include <mbedtls/x509_crt.h> 33 #include <mbedtls/error.h> 46 Thread = std::thread([
this] { this->
Run(); });
56 int64_t t_sleep =
Period * 0.7;
59 std::unique_lock<std::mutex> lock(
Mutex);
60 std::cv_status status =
Condition.wait_for(lock, std::chrono::milliseconds(t_sleep));
62 if (status == std::cv_status::no_timeout)
82 LOG_DEBUG(
Logger,
"keep_alive_thread | read a variable from address space to keep session open");
106 catch (std::system_error & ex)
108 LOG_ERROR(
Logger,
"keep_alive_thread | exception thrown at attempt to join: {}", ex.what());
140 params.SecurePolicy =
"http://opcfoundation.org/UA/SecurityPolicy#None";
157 filter.
ProfileUris.push_back(
"http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
158 filter.
LocaleIds.push_back(
"http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
159 std::vector<EndpointDescription> endpoints =
Server->Endpoints()->GetEndpoints(filter);
168 LOG_DEBUG(
Logger,
"ua_client | going through server endpoints and selected one we support");
171 bool has_login = !uri.
User().empty();
175 LOG_DEBUG(
Logger,
"ua_client | examining endpoint: {} with security: {}", ed.EndpointUrl, ed.SecurityPolicyUri);
177 if (ed.SecurityPolicyUri ==
"http://opcfoundation.org/UA/SecurityPolicy#None")
179 LOG_DEBUG(
Logger,
"ua_client | security policy is OK, now looking at user token");
181 if (ed.UserIdentityTokens.empty())
210 throw std::runtime_error(
"No supported endpoints found on server");
228 params.SecurePolicy =
"http://opcfoundation.org/UA/SecurityPolicy#None";
260 bool user_identify_token_found =
false;
267 for (
auto token : ep.UserIdentityTokens)
274 user_identify_token_found =
true;
286 if (token.SecurityPolicyUri !=
"http://opcfoundation.org/UA/SecurityPolicy#None")
291 user_identify_token_found =
true;
299 if (!user_identify_token_found)
301 throw std::runtime_error(
"Cannot find suitable user identify token for session");
323 channelparams.
ClientNonce = std::vector<uint8_t>(1, 0);
372 if (!
Server) {
throw std::runtime_error(
"Not connected");}
375 return namespacearray.
GetValue().
As<std::vector<std::string>>();;
380 if (!
Server) {
throw std::runtime_error(
"Not connected");}
383 std::vector<std::string> uris = namespacearray.
GetValue().
As<std::vector<std::string>>();;
385 for (uint32_t i = 0; i < uris.size(); ++i)
393 throw std::runtime_error(
"Error namespace uri does not exists in server");
405 if (!
Server) {
throw std::runtime_error(
"Not connected");}
412 if (!
Server) {
throw std::runtime_error(
"Not connected");}
419 if (!
Server) {
throw std::runtime_error(
"Not connected");}
426 if (!
Server) {
throw std::runtime_error(
"Not connected");}
435 std::vector<OpcUa::Node> children =
AddChilds(nodes);
436 nodes.insert(nodes.end(), children.begin(), children.end());
441 std::vector<OpcUa::DeleteNodesItem> nodesToDelete;
442 nodesToDelete.resize(nodes.size());
444 for (
unsigned i = 0; i < nodes.size(); i++)
446 nodesToDelete[i].NodeId = nodes[i].GetId();
447 nodesToDelete[i].DeleteTargetReferences =
true;
452 for (std::vector<OpcUa::StatusCode>::iterator it = response.
Results.begin(); it < response.
Results.end(); it++)
460 std::vector<OpcUa::Node> results;
461 std::vector<OpcUa::Node> temp;
463 for (std::vector<OpcUa::Node>::iterator it = nodes.begin(); it < nodes.end(); it++)
466 temp = it->GetChildren();
470 results.insert(results.begin(), temp.begin(), temp.end());
472 results.insert(results.begin(), temp.begin(), temp.end());
484 return std::make_shared<Subscription>(
Server, params, callback,
Logger);
498 #ifdef SSL_SUPPORT_MBEDTLS 505 std::stringstream stream;
506 stream << std::setfill (
'0') << std::setw(
sizeof(i)*2) <<
std::hex << i;
511 mbedtls_strerror(err_no, buff,
sizeof(buff));
512 return "-" + int_to_hex(-err_no) +
": " +
std::string(buff);
514 auto hex = [](
const std::vector<unsigned char> &bytes)
517 for(
unsigned char c : bytes) {
518 auto val_to_digit = [](
unsigned char c) {
return (
c >= 10)?
c-10+
'a':
c+
'0'; };
519 ret.push_back(val_to_digit(
c/16));
520 ret.push_back(val_to_digit(
c%16));
524 mbedtls_x509_crt x509;
525 mbedtls_x509_crt_init( &x509 );
529 LOG_ERROR(
Logger,
"ua_client | error loading server certificate {}", error2string(ret) );
533 mbedtls_entropy_context entropy;
534 mbedtls_ctr_drbg_context ctr_drbg;
535 const char pers[] =
"freeopcua_ua_client";
537 mbedtls_ctr_drbg_init( &ctr_drbg );
538 mbedtls_entropy_init( &entropy );
540 LOG_DEBUG(
Logger,
"ua_client | seeding the random number generator...");
541 ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, (
const unsigned char *) pers,
sizeof(pers) );
543 LOG_ERROR(
Logger,
"ua_client | error seeding the random number generator {}", error2string(ret) );
547 mbedtls_rsa_context *rsa = mbedtls_pk_rsa(x509.pk);
548 rsa->padding = MBEDTLS_RSA_PKCS_V21;
549 rsa->hash_id = MBEDTLS_MD_SHA1;
551 LOG_DEBUG(
Logger,
"ua_client | generating the RSA encrypted value...");
553 unsigned char buff[rsa->len];
558 size_t l = input.length();
559 for (
size_t i = 0; i < l; ++i) {
560 unsigned char n = l % 256;
567 ret = mbedtls_rsa_pkcs1_encrypt( rsa, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PUBLIC, input.size(), (
const unsigned char*)input.data(), buff );
569 LOG_ERROR(
Logger,
"ua_client | error RSA encryption {}", error2string(ret) );
572 LOG_DEBUG(
Logger,
"ua_client | encrypted password: {}",
hex(std::vector<unsigned char>(buff, buff +
sizeof(buff))));
578 mbedtls_ctr_drbg_free( &ctr_drbg );
579 mbedtls_entropy_free( &entropy );
582 mbedtls_x509_crt_free( &x509 );
std::condition_variable Condition
OpcUa::ByteString ServerNonce
std::string Password() const
OpcUa::ResponseHeader Header
Node GetNode(const NodeId &nodeid) const
Get a specific node by nodeid.
void CheckStatusCode(StatusCode code)
OpcUa Error codes. GNU LGPL.
void setUser(const std::string &user, const std::string &password)
virtual void EncryptPassword(OpcUa::UserIdentifyToken &identity, const CreateSessionResponse &response)
UaClient(bool debug=false)
create high level client this class is meant to be used to quickly/easily connect to an OPCUA server ...
ApplicationDescription ClientDescription
IntFormatSpec< int, TypeSpec<'x'> > hex(int value)
std::vector< OpcUa::EndpointDescription > ServerEndpoints
OpcUa::SignatureData ClientSignature
double RequestedPublishingInterval
std::string EncryptionAlgorithm
MessageSecurityMode SecurityMode
Services::SharedPtr Server
OpcUa::ByteString ServerCertificate
#define LOG_ERROR(__logger__,...)
void DeleteNodes(std::vector< OpcUa::Node > &nodes, bool recursive=false)
#define LOG_DEBUG(__logger__,...)
KeepAliveThread KeepAlive
std::vector< uint8_t > Data
std::vector< EndpointDescription > GetServerEndpoints()
get endpoints from server, assume we are already connected
std::atomic< bool > Running
void Disconnect()
Disconnect from server.
Node GetRootNode() const
helper methods for node you will probably want to access
OpcUa::CreateSessionResult Parameters
Node GetServerNode() const
std::shared_ptr< logger > get(const std::string &name)
OpcUa::ApplicationDescription Server
#define LOG_INFO(__logger__,...)
void SetLogger(const Common::Logger::SharedPtr &logger)
void Connect(const std::string &endpoint)
connect to a server, specify endpoint as string
void Abort()
Abort server connection.
uint32_t GetNamespaceIndex(std::string uri)
Services::SharedPtr CreateBinaryClient(IOChannel::SharedPtr channel, const SecureConnectionParams ¶ms, const Common::Logger::SharedPtr &logger=nullptr)
Create server based on opc ua binary protocol.
OpcUa::ApplicationType ApplicationType
uint32_t ClientProtocolVersion
std::string ApplicationUri
Common::Logger::SharedPtr Logger
SecurityToken ChannelSecurityToken
OPC UA Address space part. GNU LGPL.
std::string ApplicationUri
ServerOperations CreateServerOperations()
Create a server operations object.
std::vector< std::string > GetServerNamespaces()
Get namespaces used by server.
Node GetObjectsNode() const
std::vector< uint8_t > ClientNonce
std::vector< OpcUa::Node > AddChilds(std::vector< OpcUa::Node > nodes)
std::vector< std::string > LocaleIds
Subscription::SharedPtr CreateSubscription(unsigned int period, SubscriptionHandler &client)
Create a subscription objects.
OpcUa::LocalizedText ApplicationName
EndpointDescription Endpoint
A Node object represent an OPC-UA node. It is high level object intended for developper who want to e...
NodeId ToNodeId(const std::string &str, uint32_t defaultNamespace=0)
OpcUa::UserIdentifyToken UserIdentityToken
double RevisedSessionTimeout
std::string ToString(const AttributeId &value)
OpcUa::UserTokenType TokenType
SecurityTokenRequestType RequestType
Services::SharedPtr Server
void Start(Services::SharedPtr server, Node node, Duration period)
std::atomic< bool > StopRequest
void CloseSecureChannel()
OpcUa::ResponseHeader Header
void setPolicyId(const std::string &id)
std::shared_ptr< logger > stderr_color_mt(const std::string &logger_name)
Common::Logger::SharedPtr Logger
std::unique_ptr< RemoteConnection > Connect(const std::string &host, unsigned port, const Common::Logger::SharedPtr &logger)
std::vector< std::string > ProfileUris
std::vector< OpcUa::StatusCode > Results
struct OpcUa::UserIdentifyToken::UserNameStruct UserName
EndpointDescription SelectEndpoint(const std::string &)
Connect to server and select one endpoint.