Coverage Report

Created: 2026-10-03 06:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541_15/src/client/ua_client_connect.c
Line
Count
Source
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
 *
5
 *    Copyright 2017-2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
6
 *    Copyright 2017-2019 (c) Fraunhofer IOSB (Author: Mark Giraud)
7
 *    Copyright 2025 (c) Siemens AG (Author: Tin Raic)
8
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
9
 */
10
11
#include <open62541/types.h>
12
13
#include "open62541/transport_generated.h"
14
#include "ua_client_internal.h"
15
#include "../ua_types_encoding_binary.h"
16
#include "mp_printf.h"
17
18
/* Some OPC UA servers only return all Endpoints if the EndpointURL used during
19
 * the HEL/ACK handshake exactly matches -- including the path following the
20
 * address and port! Hence for the first connection we only call FindServers and
21
 * reopen a new TCP connection using then EndpointURL found there.
22
 *
23
 * The overall process is this:
24
 * - Connect with the EndpointURL provided by the user (HEL/ACK)
25
 * - Call FindServers
26
 *   - If one of the results has an exactly matching EndpointUrl, continue.
27
 *   - Otherwise select a matching server, update the endpointURL member of
28
 *     UA_Client and reconnect.
29
 * - Call GetEndpoints and select an Endpoint
30
 * - Open a SecureChannel and Session for that Endpoint
31
 * - Read the namespaces array of the server (and create the namespaces mapping)
32
 */
33
34
0
#define UA_MINMESSAGESIZE 8192
35
0
#define MAX_DATA_SIZE 4096
36
37
static void initConnect(UA_Client *client);
38
static UA_StatusCode createSessionAsync(UA_Client *client);
39
static UA_UserTokenPolicy *
40
findUserTokenPolicy(UA_Client *client, UA_EndpointDescription *endpoint,
41
                    char *logPrefix);
42
43
/* Get the EndpointUrl to be used right now.
44
 * This is adjusted during the discovery process.
45
 * We fall back if connecting to an EndpointUrl fails. */
46
static UA_String
47
0
getEndpointUrl(UA_Client *client) {
48
0
    if(client->endpoint.endpointUrl.length > 0)
49
0
        return client->endpoint.endpointUrl;
50
0
    if(client->discoveryUrl.length > 0)
51
0
        return client->discoveryUrl;
52
0
    return client->config.endpointUrl;
53
0
}
54
55
/* If an EndpointUrl doesn't work (TCP connection fails), fall back to the
56
 * initial EndpointUrl */
57
static UA_StatusCode
58
0
fallbackEndpointUrl(UA_Client* client) {
59
    /* Cannot fallback, the initial EndpointUrl is already in use */
60
0
    UA_String currentUrl = getEndpointUrl(client);
61
0
    if(UA_String_equal(&currentUrl, &client->config.endpointUrl)) {
62
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
63
0
                     "Could not open a TCP connection to the Endpoint at %S",
64
0
                     client->config.endpointUrl);
65
0
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
66
0
    }
67
68
0
    if(client->endpoint.endpointUrl.length > 0) {
69
        /* Overwrite the EndpointUrl of the Endpoint */
70
0
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
71
0
                       "Could not open a TCP connection to the Endpoint at %S. "
72
0
                       "Overriding the endpoint description with the initial "
73
0
                       "EndpointUrl at %S.",
74
0
                       client->config.endpoint.endpointUrl,
75
0
                       client->config.endpointUrl);
76
0
        UA_String_clear(&client->endpoint.endpointUrl);
77
0
        return UA_String_copy(&client->config.endpointUrl,
78
0
                              &client->endpoint.endpointUrl);
79
0
    } else {
80
        /* Overwrite the DiscoveryUrl returned by FindServers */
81
0
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
82
0
                       "The DiscoveryUrl returned by the FindServers service (%S) "
83
0
                       "could not be connected. Continuing with the initial EndpointUrl "
84
0
                       "%S for the GetEndpoints service.",
85
0
                       client->config.endpointUrl, client->config.endpointUrl);
86
0
        UA_String_clear(&client->discoveryUrl);
87
0
        return UA_String_copy(&client->config.endpointUrl, &client->discoveryUrl);
88
0
    }
89
0
}
90
91
static UA_SecurityPolicy *
92
0
getSecurityPolicy(UA_Client *client, UA_String policyUri) {
93
0
    for(size_t i = 0; i < client->config.securityPoliciesSize; i++) {
94
0
        if(UA_String_equal(&policyUri, &client->config.securityPolicies[i].policyUri))
95
0
            return &client->config.securityPolicies[i];
96
0
    }
97
0
    return NULL;
98
0
}
99
100
/* Match PolicyUri and certificate. The returned SecurityPolicy instance carries
101
 * the private key to sign with the given certificate. When the certificate is
102
 * NULL, only the PolicyUri is matched (used for non-X509 token types). */
103
static UA_SecurityPolicy *
104
getAuthSecurityPolicy(UA_Client *client, const UA_String policyUri,
105
0
                      const UA_ByteString *certificate) {
106
0
    for(size_t i = 0; i < client->config.authSecurityPoliciesSize; i++) {
107
0
        UA_SecurityPolicy *sp = &client->config.authSecurityPolicies[i];
108
0
        if(!UA_String_equal(&policyUri, &sp->policyUri))
109
0
            continue;
110
0
        if(certificate && !UA_ByteString_equal(certificate, &sp->localCertificate))
111
0
            continue;
112
0
        return sp;
113
0
    }
114
0
    return NULL;
115
0
}
116
117
/* The endpoint is unconfigured if the description is all zeroed-out */
118
static UA_Boolean
119
0
endpointUnconfigured(const UA_EndpointDescription *endpoint) {
120
0
    UA_EndpointDescription tmp;
121
0
    UA_EndpointDescription_init(&tmp);
122
0
    return UA_equal(&tmp, endpoint, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
123
0
}
124
125
UA_Boolean
126
0
isFullyConnected(UA_Client *client) {
127
    /* No SecureChannel */
128
0
    if(client->channel.state != UA_SECURECHANNELSTATE_OPEN)
129
0
        return false;
130
131
    /* GetEndpoints handshake ongoing or not yet done */
132
0
    if(client->endpointsHandshake || endpointUnconfigured(&client->endpoint))
133
0
        return false;
134
135
    /* FindServers handshake ongoing or not yet done */
136
0
    if(client->findServersHandshake || client->discoveryUrl.length == 0)
137
0
        return false;
138
139
0
    if(!client->config.noSession) {
140
        /* No Session, but is required */
141
0
        if(client->sessionState != UA_SESSIONSTATE_ACTIVATED)
142
0
            return false;
143
144
        /* NamespaceArray not yet read */
145
0
        if(client->namespacesHandshake || !client->haveNamespaces)
146
0
            return false;
147
0
    }
148
149
0
    return true;
150
0
}
151
152
static UA_StatusCode
153
initUserTokenPolicy(UA_Client *client, const UA_UserTokenPolicy **outUtp,
154
0
                    char *logPrefix) {
155
0
    const UA_UserTokenPolicy *utp =
156
0
        findUserTokenPolicy(client, &client->endpoint, logPrefix);
157
0
    if(!utp) {
158
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
159
0
                     "%s: Could not find a matching UserTokenPolicy "
160
0
                     "in the endpoint", logPrefix);
161
0
        return UA_STATUSCODE_BADSECURITYPOLICYREJECTED;
162
0
    }
163
164
0
    UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
165
0
                "%s: Using UserTokenPolicy %S", logPrefix, utp->policyId);
166
167
    /* If not specifically defined in the UserTokenPolicy, then the
168
     * SecurityPolicy of the underlying endpoint (SecureChannel) is used. */
169
0
    UA_String tokenSecurityPolicyUri = (utp->securityPolicyUri.length > 0) ?
170
0
        utp->securityPolicyUri : client->endpoint.securityPolicyUri;
171
172
    /* Get the SecurityPolicy for the UserIdentityToken. X509 tokens sign with
173
     * a private key, so they must use an authSecurityPolicy (matched by
174
     * PolicyUri and certificate). Other tokens only encrypt with the server
175
     * certificate, so fall back to the SecureChannel securityPolicies. */
176
0
    UA_SecurityPolicy *utsp;
177
0
    if(utp->tokenType == UA_USERTOKENTYPE_CERTIFICATE) {
178
0
        UA_X509IdentityToken *token = (UA_X509IdentityToken*)
179
0
            client->config.userIdentityToken.content.decoded.data;
180
0
        utsp = getAuthSecurityPolicy(client, tokenSecurityPolicyUri,
181
0
                                     &token->certificateData);
182
0
    } else {
183
0
        utsp = getAuthSecurityPolicy(client, tokenSecurityPolicyUri, NULL);
184
0
        if(!utsp)
185
0
            utsp = getSecurityPolicy(client, tokenSecurityPolicyUri);
186
0
    }
187
0
    if(!utsp) {
188
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
189
0
                     "%s: SecurityPolicy %S not available for the "
190
0
                     "UserTokenPolicy", logPrefix, tokenSecurityPolicyUri);
191
0
        return UA_STATUSCODE_BADSECURITYPOLICYREJECTED;
192
0
    }
193
194
    /* ExistingSecurityPolicy matches? */
195
0
    if(client->utpSp) {
196
0
        if(!UA_String_equal(&client->utpSp->policyUri,
197
0
                            &tokenSecurityPolicyUri)) {
198
0
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
199
0
                         "%s: SecurityPolicy %S cannot be instantiated. "
200
0
                         "A different SecurityPolicy %S is in place already",
201
0
                         logPrefix, tokenSecurityPolicyUri,
202
0
                         client->utpSp->policyUri);
203
0
            return UA_STATUSCODE_BADSECURITYPOLICYREJECTED;
204
0
        }
205
206
        /* Set the output and return */
207
0
        *outUtp = utp;
208
0
        return UA_STATUSCODE_GOOD;
209
0
    }
210
211
    /* Create an instance of the SecurityPolicy using the server certificate
212
     * from the endpoint */
213
0
    UA_StatusCode res =
214
0
        utsp->newChannelContext(utsp, &client->endpoint.serverCertificate,
215
0
                                &client->utpSpContext);
216
0
    if(res != UA_STATUSCODE_GOOD) {
217
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
218
0
                     "%s: UserTokenPolicy %S could not be instantiated with the "
219
0
                     "server certificate", logPrefix, tokenSecurityPolicyUri);
220
0
        return UA_STATUSCODE_BADSECURITYPOLICYREJECTED;
221
0
    }
222
0
    client->utpSp = utsp;
223
224
    /* Set the output and return */
225
0
    *outUtp = utp;
226
0
    return UA_STATUSCODE_GOOD;
227
0
}
228
229
/* Legacy (pre-v1.05.07) signature: the leaf of the remote (peer) certificate
230
 * concatenated with the server's session nonce, signed with the given
231
 * SecurityPolicy/context. Shared by the application ClientSignature and the
232
 * X.509 user-token signature. The leaf is used (not the raw, possibly-chained
233
 * remoteCertificate) so the bytes match the server's verify, which is computed
234
 * over its single localCertificate. */
235
static UA_StatusCode
236
signLegacyCertNonce(const UA_SecurityPolicy *sp, void *spContext,
237
                    const UA_ByteString *remoteCertificate,
238
0
                    const UA_ByteString *serverNonce, UA_ByteString *outSignature) {
239
0
    UA_ByteString leaf = getLeafCertificate(*remoteCertificate);
240
0
    size_t signDataSize = leaf.length + serverNonce->length;
241
0
    if(signDataSize > MAX_DATA_SIZE)
242
0
        return UA_STATUSCODE_BADINTERNALERROR;
243
0
    UA_Byte buf[MAX_DATA_SIZE];
244
0
    UA_ByteString signData = {signDataSize, buf};
245
0
    memcpy(buf, leaf.data, leaf.length);
246
0
    memcpy(buf + leaf.length, serverNonce->data, serverNonce->length);
247
0
    return sp->asymSignatureAlgorithm.sign(sp, spContext, &signData, outSignature);
248
0
}
249
250
/* Function to create a signature using remote certificate and nonce.
251
 * This uses the SecurityPolicy of the SecureChannel. */
252
static UA_StatusCode
253
0
signClientSignature(UA_Client *client, UA_ActivateSessionRequest *request) {
254
0
    UA_SecureChannel *channel = &client->channel;
255
0
    const UA_SecurityPolicy *sp = channel->securityPolicy;
256
0
    void *cc = channel->channelContext;
257
258
0
    UA_SignatureData *sd = &request->clientSignature;
259
0
    const UA_SecurityPolicySignatureAlgorithm *signAlg = &sp->asymSignatureAlgorithm;
260
261
    /* OPC UA Part 4 v1.05.07: for SecurityPolicies with
262
     * secureChannelEnhancements = true, the algorithm field in
263
     * SignatureData shall be NULL or empty and receivers shall
264
     * ignore the value. */
265
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
266
0
    if(!UA_SecurityPolicy_isEnhancedSecurity(sp))
267
0
        retval = UA_String_copy(&signAlg->uri, &sd->algorithm);
268
0
    if(retval != UA_STATUSCODE_GOOD)
269
0
        return retval;
270
271
    /* Allocate memory for the signature */
272
0
    size_t signatureSize = signAlg->getLocalSignatureSize(sp, cc);
273
0
    retval = UA_ByteString_allocBuffer(&sd->signature, signatureSize);
274
0
    if(retval != UA_STATUSCODE_GOOD)
275
0
        return retval;
276
277
0
    if(UA_SecurityPolicy_isEnhancedSecurity(sp)) {
278
        /* Channel-bound v1.05.07 ClientSignature (see the cert-role table at
279
         * UA_SecureChannel_buildActivateSessionSignatureData). */
280
0
        UA_ByteString signData = UA_BYTESTRING_NULL;
281
0
        retval = UA_SecureChannel_buildActivateSessionSignatureData(
282
0
            channel, &client->serverSessionNonce, &client->clientSessionNonce,
283
0
            &channel->remoteCertificate, &channel->remoteCertificate,
284
0
            &sp->localCertificate, &signData);
285
0
        if(retval != UA_STATUSCODE_GOOD)
286
0
            return retval;
287
0
        retval = signAlg->sign(sp, cc, &signData, &sd->signature);
288
0
        UA_ByteString_clear(&signData);
289
0
        return retval;
290
0
    }
291
292
    /* Legacy (v1.05.06): leaf(serverCert) + serverNonce. */
293
0
    return signLegacyCertNonce(sp, cc, &channel->remoteCertificate,
294
0
                               &client->serverSessionNonce, &sd->signature);
295
0
}
296
297
/* This uses the SecurityPolicy of the UserTokenPolicy */
298
static UA_StatusCode
299
signUserTokenSignature(UA_Client *client,
300
0
                       UA_ActivateSessionRequest *request) {
301
0
    UA_assert(client->config.userIdentityToken.content.decoded.type ==
302
0
              &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN]);
303
304
0
    UA_SecurityPolicy *utpSp = client->utpSp;
305
0
    UA_assert(utpSp);
306
307
0
    UA_SecureChannel *channel = &client->channel;
308
0
    UA_SecurityPolicySignatureAlgorithm *signAlg = &utpSp->asymSignatureAlgorithm;
309
0
    UA_SignatureData *utsd = &request->userTokenSignature;
310
311
    /* Stricter servers reject an empty user-token algorithm - so always send
312
     * the policy's signature URI (the AesGcm policy carries its SecurityPolicy
313
     * URI there; RSA carries the RSA URI; plain ECC carries an empty
314
     * string). */
315
0
    UA_StatusCode retval = UA_String_copy(&signAlg->uri, &utsd->algorithm);
316
0
    if(retval != UA_STATUSCODE_GOOD)
317
0
        return retval;
318
319
    /* Allocate memory for the signature */
320
0
    size_t sigLen = signAlg->getLocalSignatureSize(utpSp, client->utpSpContext);
321
0
    retval = UA_ByteString_allocBuffer(&utsd->signature, sigLen);
322
0
    if(retval != UA_STATUSCODE_GOOD)
323
0
        return retval;
324
325
    /* Channel-bound v1.05.07 user-token signature (see the cert-role table at
326
     * UA_SecureChannel_buildUserTokenSignatureData), produced with the user's
327
     * private key (utpSp context). Used only when BOTH the SecureChannel AND the
328
     * user-token SecurityPolicy are enhanced; a legacy RSA / old-ECC user token
329
     * uses the legacy layout even over an enhanced (AesGcm) SecureChannel. */
330
0
    if(UA_SecurityPolicy_isEnhancedSecurity(channel->securityPolicy) &&
331
0
       UA_SecurityPolicy_isEnhancedSecurity(utpSp)) {
332
0
        const UA_ByteString *clientCert = &channel->securityPolicy->localCertificate;
333
0
        UA_ByteString signData = UA_BYTESTRING_NULL;
334
0
        retval = UA_SecureChannel_buildUserTokenSignatureData(
335
0
            channel, &client->serverSessionNonce, &client->clientSessionNonce,
336
0
            &channel->remoteCertificate, &channel->remoteCertificate,
337
0
            clientCert, clientCert, &signData);
338
0
        if(retval == UA_STATUSCODE_GOOD)
339
0
            retval = signAlg->sign(utpSp, client->utpSpContext, &signData, &utsd->signature);
340
0
        UA_ByteString_clear(&signData);
341
0
        return retval;
342
0
    }
343
344
    /* Legacy (v1.05.06): leaf(serverCert) + serverNonce (same as the
345
     * application ClientSignature), signed with the user's key. */
346
0
    return signLegacyCertNonce(utpSp, client->utpSpContext,
347
0
                               &channel->remoteCertificate,
348
0
                               &client->serverSessionNonce, &utsd->signature);
349
0
}
350
351
/* UserName and IssuedIdentity can be encrypted. This uses the SecurityPolicy
352
 * instance for the UserTokenPolicy. So it can keep the ECC ephemeral keys
353
 * across multiple SecureChannels. */
354
static UA_StatusCode
355
0
encryptUserIdentityToken(UA_Client *client, UA_ExtensionObject *userIdentityToken) {
356
0
    UA_IssuedIdentityToken *iit = NULL;
357
0
    UA_UserNameIdentityToken *unit = NULL;
358
0
    UA_String *encryptionAlg;
359
0
    UA_ByteString *tokenData;
360
361
0
    const UA_DataType *tokenType = userIdentityToken->content.decoded.type;
362
0
    if(tokenType == &UA_TYPES[UA_TYPES_ISSUEDIDENTITYTOKEN]) {
363
0
        iit = (UA_IssuedIdentityToken*)userIdentityToken->content.decoded.data;
364
0
        tokenData = &iit->tokenData;
365
0
        encryptionAlg = &iit->encryptionAlgorithm;
366
0
    } else { /* tokenType == &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN] */
367
0
        UA_assert(tokenType == &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]);
368
0
        unit = (UA_UserNameIdentityToken*)userIdentityToken->content.decoded.data;
369
0
        tokenData = &unit->password;
370
0
        encryptionAlg = &unit->encryptionAlgorithm;
371
0
    }
372
373
    /* The sessionSp is instantiated during CreateSession */
374
0
    UA_SecurityPolicy *utpSp = client->utpSp;
375
0
    UA_assert(utpSp);
376
377
    /* Nothing to encrypt */
378
0
    if(utpSp->policyType == UA_SECURITYPOLICYTYPE_NONE) {
379
        /* Warn if a token is transmitted in cleartext. This needs to be allowed
380
         * with the allowNonePolicyPassword setting and is checked in
381
         * findUserTokenPolicy. */
382
0
        if(client->channel.securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
383
0
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
384
0
                           "!!! Warning !!! AuthenticationToken is transmitted "
385
0
                           "without encryption");
386
0
        return UA_STATUSCODE_GOOD;
387
0
    }
388
389
    /* Encrypt the TokenData */
390
0
    UA_StatusCode res = UA_STATUSCODE_GOOD;
391
0
    if(UA_SecurityPolicy_isEcc(utpSp)) {
392
0
        res = encryptUserIdentityTokenEcc(client->config.logging, &client->channel,
393
0
                                          utpSp, client->utpSpContext, tokenData,
394
0
                                          client->serverSessionNonce,
395
0
                                          client->serverEphemeralPubKey);
396
        /* Don't reuse the Ephemeral Public Key */
397
0
        UA_ByteString_clear(&client->serverEphemeralPubKey);
398
399
        /* The EccEncryptedSecret identifies its algorithm via the SecurityPolicy
400
         * URI embedded in the secret header, so the UserIdentityToken's
401
         * encryptionAlgorithm field is left EMPTY (matching the OPC UA reference
402
         * stack, which sets it to null for the EncryptedSecret format). Sending
403
         * the policy's asymEncryptionAlgorithm URI here makes strict servers
404
         * reject the token with BadIdentityTokenInvalid */
405
0
        return res;
406
0
    }
407
408
0
    res = encryptSecretLegacy(utpSp, client->utpSpContext,
409
0
                              client->serverSessionNonce, tokenData);
410
411
    /* Legacy RSA EncryptedData: carry the asymmetric encryption algorithm URI */
412
0
    return res | UA_String_copy(&utpSp->asymEncryptionAlgorithm.uri, encryptionAlg);
413
0
}
414
415
/* Verifies the signature corresponds to ClientNonce using the SecurityPolicy of
416
 * the SecureChannel */
417
static UA_StatusCode
418
checkCreateSessionSignature(UA_Client *client, const UA_SecureChannel *channel,
419
0
                            const UA_CreateSessionResponse *response) {
420
0
    if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGN &&
421
0
       channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
422
0
        return UA_STATUSCODE_GOOD;
423
424
0
    if(!channel->securityPolicy)
425
0
        return UA_STATUSCODE_BADINTERNALERROR;
426
427
0
    const UA_SecurityPolicy *sp = channel->securityPolicy;
428
0
    const UA_ByteString *lc = &sp->localCertificate;
429
430
0
    UA_ByteString dataToVerify = UA_BYTESTRING_NULL;
431
0
    UA_StatusCode retval;
432
0
    if(UA_SecurityPolicy_isEnhancedSecurity(sp)) {
433
        /* Channel-bound v1.05.07 CreateSession ServerSignature (see the
434
         * cert-role table at UA_SecureChannel_buildCreateSessionSignatureData). */
435
0
        retval = UA_SecureChannel_buildCreateSessionSignatureData(
436
0
            channel, &client->clientSessionNonce, &response->serverNonce,
437
0
            &channel->remoteCertificate, lc, &dataToVerify);
438
0
    } else {
439
0
        retval = UA_ByteString_allocBuffer(&dataToVerify,
440
0
                                           lc->length + client->clientSessionNonce.length);
441
0
        if(retval == UA_STATUSCODE_GOOD) {
442
0
            memcpy(dataToVerify.data, lc->data, lc->length);
443
0
            memcpy(dataToVerify.data + lc->length, client->clientSessionNonce.data,
444
0
                   client->clientSessionNonce.length);
445
0
        }
446
0
    }
447
0
    if(retval != UA_STATUSCODE_GOOD)
448
0
        return retval;
449
450
0
    const UA_SecurityPolicySignatureAlgorithm *signAlg = &sp->asymSignatureAlgorithm;
451
0
    retval = signAlg->verify(sp, channel->channelContext, &dataToVerify,
452
0
                             &response->serverSignature.signature);
453
0
    UA_ByteString_clear(&dataToVerify);
454
0
    return retval;
455
0
}
456
457
/***********************/
458
/* Open the Connection */
459
/***********************/
460
461
void
462
0
processERRResponse(UA_Client *client, const UA_ByteString *chunk) {
463
0
    size_t offset = 0;
464
0
    UA_TcpErrorMessage errMessage;
465
0
    UA_StatusCode res =
466
0
        UA_decodeBinaryInternal(chunk, &offset, &errMessage,
467
0
                                &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE], NULL);
468
0
    if(res != UA_STATUSCODE_GOOD) {
469
0
        UA_LOG_ERROR_CHANNEL(client->config.logging, &client->channel,
470
0
                             "Received an ERR response that could not be decoded "
471
0
                             "with StatusCode %s", UA_StatusCode_name(res));
472
0
        setConnectStatus(client, res);
473
0
        return;
474
0
    }
475
476
0
    UA_LOG_ERROR_CHANNEL(client->config.logging, &client->channel,
477
0
                         "Received an ERR response with StatusCode %s and "
478
0
                         "the following reason: \"%S\"",
479
0
                         UA_StatusCode_name(errMessage.error),
480
0
                         errMessage.reason);
481
0
    setConnectStatus(client, errMessage.error);
482
0
    UA_TcpErrorMessage_clear(&errMessage);
483
0
}
484
485
void
486
0
processACKResponse(UA_Client *client, const UA_ByteString *chunk) {
487
0
    UA_SecureChannel *channel = &client->channel;
488
0
    if(channel->state != UA_SECURECHANNELSTATE_HEL_SENT) {
489
0
        UA_LOG_ERROR_CHANNEL(client->config.logging, channel,
490
0
                             "SecureChannel not in the HEL-sent state");
491
0
        setConnectStatus(client, UA_STATUSCODE_BADSECURECHANNELCLOSED);
492
0
        return;
493
0
    }
494
495
    /* Decode the message */
496
0
    size_t offset = 0;
497
0
    UA_TcpAcknowledgeMessage ackMessage;
498
0
    UA_StatusCode res =
499
0
        UA_decodeBinaryInternal(chunk, &offset, &ackMessage,
500
0
                                &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE], NULL);
501
0
    if(res != UA_STATUSCODE_GOOD) {
502
0
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_NETWORK,
503
0
                     "Decoding ACK message failed");
504
0
        setConnectStatus(client, res);
505
0
        return;
506
0
    }
507
508
0
    res = UA_SecureChannel_processHELACK(channel, &ackMessage);
509
0
    if(res != UA_STATUSCODE_GOOD) {
510
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_NETWORK,
511
0
                     "Processing the ACK message failed with StatusCode %s",
512
0
                     UA_StatusCode_name(res));
513
0
        setConnectStatus(client, res);
514
0
        return;
515
0
    }
516
517
0
    client->channel.state = UA_SECURECHANNELSTATE_ACK_RECEIVED;
518
0
}
519
520
static UA_StatusCode
521
0
sendHELMessage(UA_Client *client) {
522
0
    UA_ConnectionManager *cm = client->channel.connectionManager;
523
0
    if(!UA_SecureChannel_isConnected(&client->channel))
524
0
        return UA_STATUSCODE_BADNOTCONNECTED;
525
526
    /* Get a buffer */
527
0
    UA_ByteString message;
528
0
    UA_StatusCode retval = cm->allocNetworkBuffer(cm, client->channel.connectionId,
529
0
                                                  &message, UA_MINMESSAGESIZE);
530
0
    if(retval != UA_STATUSCODE_GOOD)
531
0
        return retval;
532
533
    /* Prepare the HEL message and encode at offset 8 */
534
0
    UA_TcpHelloMessage hello;
535
0
    hello.protocolVersion = 0;
536
0
    hello.receiveBufferSize = client->config.localConnectionConfig.recvBufferSize;
537
0
    hello.sendBufferSize = client->config.localConnectionConfig.sendBufferSize;
538
0
    hello.maxMessageSize = client->config.localConnectionConfig.localMaxMessageSize;
539
0
    hello.maxChunkCount = client->config.localConnectionConfig.localMaxChunkCount;
540
0
    hello.endpointUrl = getEndpointUrl(client);
541
542
0
    UA_Byte *bufPos = &message.data[8]; /* skip the header */
543
0
    const UA_Byte *bufEnd = &message.data[message.length];
544
0
    retval = UA_encodeBinaryInternal(&hello, &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE],
545
0
                                     &bufPos, &bufEnd, NULL, NULL, NULL);
546
0
    if(retval != UA_STATUSCODE_GOOD) {
547
0
        cm->freeNetworkBuffer(cm, client->channel.connectionId, &message);
548
0
        return retval;
549
0
    }
550
551
    /* Encode the message header at offset 0 */
552
0
    UA_TcpMessageHeader messageHeader;
553
0
    messageHeader.messageTypeAndChunkType = UA_CHUNKTYPE_FINAL + UA_MESSAGETYPE_HEL;
554
0
    messageHeader.messageSize = (UA_UInt32) ((uintptr_t)bufPos - (uintptr_t)message.data);
555
0
    bufPos = message.data;
556
0
    retval = UA_encodeBinaryInternal(&messageHeader,
557
0
                                     &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER],
558
0
                                     &bufPos, &bufEnd, NULL, NULL, NULL);
559
0
    if(retval != UA_STATUSCODE_GOOD) {
560
0
        cm->freeNetworkBuffer(cm, client->channel.connectionId, &message);
561
0
        return retval;
562
0
    }
563
564
    /* Send the HEL message */
565
0
    message.length = messageHeader.messageSize;
566
0
    retval = cm->sendWithConnection(cm, client->channel.connectionId,
567
0
                                    &UA_KEYVALUEMAP_NULL, &message);
568
0
    if(retval != UA_STATUSCODE_GOOD) {
569
0
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
570
0
                    "Sending HEL failed");
571
0
        setConnectStatus(client, retval);
572
0
        return retval;
573
0
    }
574
575
0
    UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
576
0
                 "Sent HEL message");
577
578
0
    client->channel.state = UA_SECURECHANNELSTATE_HEL_SENT;
579
0
    return UA_STATUSCODE_GOOD;
580
0
}
581
582
0
void processRHEMessage(UA_Client *client, const UA_ByteString *chunk) {
583
0
    UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT, "RHE received");
584
585
0
    size_t offset = 0; /* Go to the beginning of the TcpHelloMessage */
586
0
    UA_TcpReverseHelloMessage rheMessage;
587
0
    static const UA_DataType *rheType = &UA_TRANSPORT[UA_TRANSPORT_TCPREVERSEHELLOMESSAGE];
588
0
    UA_StatusCode res = UA_decodeBinaryInternal(chunk, &offset, &rheMessage, rheType, NULL);
589
0
    if(res != UA_STATUSCODE_GOOD) {
590
0
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_NETWORK,
591
0
                     "Decoding RHE message failed");
592
0
        setConnectStatus(client, res);
593
0
        return;
594
0
    }
595
596
    /* Set the internal DisocveryUrl */
597
0
    UA_String_clear(&client->discoveryUrl);
598
0
    client->discoveryUrl = rheMessage.endpointUrl;
599
0
    UA_String_init(&rheMessage.endpointUrl);
600
0
    UA_TcpReverseHelloMessage_clear(&rheMessage);
601
602
    /* Send the HEL message */
603
0
    setConnectStatus(client, sendHELMessage(client));
604
0
}
605
606
void
607
0
processOPNResponse(UA_Client *client, const UA_ByteString *message) {
608
0
    size_t offset = 0;
609
0
    UA_NodeId responseId;
610
0
    UA_OpenSecureChannelResponse response;
611
0
    UA_NodeId expectedId = UA_NS0ID(OPENSECURECHANNELRESPONSE_ENCODING_DEFAULTBINARY);
612
613
    /* Decode the type NodeId */
614
0
    UA_StatusCode res = UA_NodeId_decodeBinary(message, &offset, &responseId);
615
0
    if(res != UA_STATUSCODE_GOOD)
616
0
        goto finish_decode;
617
618
    /* Is the response of the expected type? responseId is only needed for
619
     * this check -- clear it right away regardless of the outcome so a
620
     * heap-backed type (String/GUID/ByteString NodeId) can never leak. */
621
0
    UA_Boolean typeMatches = UA_NodeId_equal(&responseId, &expectedId);
622
0
    UA_NodeId_clear(&responseId);
623
0
    if(!typeMatches) {
624
0
        res = UA_STATUSCODE_BADDECODINGERROR;
625
0
        goto finish_decode;
626
0
    }
627
628
    /* Decode the response */
629
0
    res = UA_decodeBinaryInternal(message, &offset, &response,
630
0
                                  &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE], NULL);
631
632
0
    finish_decode:
633
0
    if(res != UA_STATUSCODE_GOOD) {
634
0
        UA_LOG_ERROR_CHANNEL(client->config.logging, &client->channel,
635
0
                             "Could not decode the OpenSecureChannelResponse");
636
0
        setConnectStatus(client, res);
637
0
        return;
638
0
    }
639
640
    /* From here on, response has been decoded and must be cleared on every
641
     * rejection as well as on success. */
642
643
    /* Check whether the nonce was reused */
644
0
    if(client->channel.securityMode != UA_MESSAGESECURITYMODE_NONE &&
645
0
       UA_ByteString_equal(&client->channel.remoteNonce, &response.serverNonce)) {
646
0
        UA_LOG_ERROR_CHANNEL(client->config.logging, &client->channel,
647
0
                             "The server reused the last nonce");
648
0
        UA_OpenSecureChannelResponse_clear(&response);
649
0
        setConnectStatus(client, UA_STATUSCODE_BADSECURITYCHECKSFAILED);
650
0
        return;
651
0
    }
652
653
    /* Check the nonce length */
654
0
    if(response.serverNonce.length < client->channel.securityPolicy->nonceLength) {
655
0
        UA_LOG_ERROR_CHANNEL(client->config.logging, &client->channel,
656
0
                             "The server nonce is too short");
657
0
        UA_OpenSecureChannelResponse_clear(&response);
658
0
        setConnectStatus(client, UA_STATUSCODE_BADSECURITYCHECKSFAILED);
659
0
        return;
660
0
    }
661
662
    /* Move the nonce out of the response */
663
0
    UA_ByteString_clear(&client->channel.remoteNonce);
664
0
    client->channel.remoteNonce = response.serverNonce;
665
0
    UA_ByteString_init(&response.serverNonce);
666
0
    UA_ResponseHeader_clear(&response.responseHeader);
667
668
    /* Replace the token. Keep the current token as the old token. Messages
669
     * might still arrive for the old token. */
670
0
    client->channel.altSecurityToken = client->channel.securityToken;
671
0
    client->channel.securityToken = response.securityToken;
672
0
    client->channel.renewState = UA_SECURECHANNELRENEWSTATE_NEWTOKEN_CLIENT;
673
674
    /* Log a warning if the SecurityToken is not "fresh". Use the normal system
675
     * clock to do the comparison. */
676
0
    UA_EventLoop *el = client->config.eventLoop;
677
0
    UA_DateTime wallClockNow = el->dateTime_now(el);
678
0
    UA_ChannelSecurityToken *st = &client->channel.securityToken;
679
0
    if(wallClockNow - st->createdAt >= UA_DATETIME_SEC * 10 ||
680
0
       wallClockNow - st->createdAt <= -UA_DATETIME_SEC * 10)
681
0
        UA_LOG_WARNING_CHANNEL(client->config.logging, &client->channel,
682
0
                               "The \"CreatedAt\" timestamp of the received "
683
0
                               "ChannelSecurityToken does not match "
684
0
                               "with the local system clock");
685
686
    /* The internal "monotonic" clock is used by the SecureChannel to validate
687
     * that the SecurityToken is still valid. The monotonic clock is independent
688
     * from the system clock getting changed or synchronized to a master clock
689
     * during runtime. */
690
0
    client->channel.securityToken.createdAt = el->dateTime_nowMonotonic(el);
691
692
    /* Response.securityToken.revisedLifetime is UInt32, we need to cast it to
693
     * DateTime=Int64. After 75% of the lifetime the renewal takes place as
694
     * described in standard */
695
0
    client->nextChannelRenewal = client->channel.securityToken.createdAt +
696
0
        (UA_DateTime) (response.securityToken.revisedLifetime *
697
0
                       (UA_Double) UA_DATETIME_MSEC * 0.75);
698
699
    /* Compute the new local keys. The remote keys are updated when a message
700
     * with the new SecurityToken is received. */
701
0
    res = UA_SecureChannel_generateLocalKeys(&client->channel);
702
0
    if(res != UA_STATUSCODE_GOOD) {
703
0
        UA_OpenSecureChannelResponse_clear(&response);
704
0
        setConnectStatus(client, res);
705
0
        return;
706
0
    }
707
708
0
    UA_Float lifetime = (UA_Float)response.securityToken.revisedLifetime / 1000;
709
0
    UA_Boolean renew = (client->channel.state == UA_SECURECHANNELSTATE_OPEN);
710
0
    if(renew) {
711
0
        UA_LOG_INFO_CHANNEL(client->config.logging, &client->channel, "SecureChannel "
712
0
                            "renewed with a revised lifetime of %.2fs", lifetime);
713
0
    } else {
714
0
        UA_LOG_INFO_CHANNEL(client->config.logging, &client->channel,
715
0
                            "SecureChannel opened with SecurityMode %s for "
716
0
                            "SecurityPolicy %S and a revised lifetime of %.2fs",
717
0
                            securityModeNames[client->channel.securityMode],
718
0
                            client->channel.securityPolicy->policyUri,
719
0
                            lifetime);
720
0
    }
721
722
0
    client->channel.state = UA_SECURECHANNELSTATE_OPEN;
723
0
    UA_OpenSecureChannelResponse_clear(&response);
724
0
}
725
726
/* OPN messges to renew the channel are sent asynchronous */
727
static UA_StatusCode
728
0
sendOPNAsync(UA_Client *client, UA_Boolean renew) {
729
0
    if(!UA_SecureChannel_isConnected(&client->channel))
730
0
        return UA_STATUSCODE_BADINTERNALERROR;
731
732
0
    UA_StatusCode res = UA_SecureChannel_generateLocalNonce(&client->channel);
733
0
    if(res != UA_STATUSCODE_GOOD)
734
0
        return res;
735
736
0
    UA_EventLoop *el = client->config.eventLoop;
737
738
    /* Prepare the OpenSecureChannelRequest */
739
0
    UA_OpenSecureChannelRequest opnSecRq;
740
0
    UA_OpenSecureChannelRequest_init(&opnSecRq);
741
0
    opnSecRq.requestHeader.timestamp = el->dateTime_now(el);
742
0
    opnSecRq.requestHeader.authenticationToken = client->authenticationToken;
743
0
    opnSecRq.securityMode = client->channel.securityMode;
744
0
    opnSecRq.clientNonce = client->channel.localNonce;
745
0
    opnSecRq.requestedLifetime = client->config.secureChannelLifeTime;
746
0
    if(renew) {
747
0
        opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_RENEW;
748
0
        UA_LOG_DEBUG_CHANNEL(client->config.logging, &client->channel,
749
0
                             "Requesting to renew the SecureChannel");
750
0
    } else {
751
0
        opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_ISSUE;
752
0
        UA_LOG_DEBUG_CHANNEL(client->config.logging, &client->channel,
753
0
                             "Requesting to open a SecureChannel");
754
0
    }
755
756
    /* Prepare the entry for the linked list */
757
0
    UA_UInt32 requestId = ++client->requestId;
758
759
    /* Send the OPN message */
760
0
    UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_SECURECHANNEL,
761
0
                 "Requesting to open a SecureChannel");
762
0
    static const UA_DataType *opnReqType = &UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST];
763
0
    res = UA_SecureChannel_sendOPN(&client->channel, requestId, &opnSecRq, opnReqType);
764
0
    if(res != UA_STATUSCODE_GOOD) {
765
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_SECURECHANNEL,
766
0
                      "Sending OPN message failed with error %s",
767
0
                      UA_StatusCode_name(res));
768
0
        return res;
769
0
    }
770
771
    /* Update the state */
772
0
    client->channel.renewState = UA_SECURECHANNELRENEWSTATE_SENT;
773
0
    if(client->channel.state < UA_SECURECHANNELSTATE_OPN_SENT)
774
0
        client->channel.state = UA_SECURECHANNELSTATE_OPN_SENT;
775
776
0
    UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_SECURECHANNEL,
777
0
                 "OPN message sent");
778
779
0
    return UA_STATUSCODE_GOOD;
780
0
}
781
782
UA_StatusCode
783
0
__Client_renewSecureChannel(UA_Client *client) {
784
0
    UA_LOCK_ASSERT(&client->clientMutex);
785
786
0
    UA_EventLoop *el = client->config.eventLoop;
787
0
    UA_DateTime now = el->dateTime_nowMonotonic(el);
788
789
    /* Check if OPN has been sent or the SecureChannel is still valid */
790
0
    if(client->channel.state != UA_SECURECHANNELSTATE_OPEN ||
791
0
       client->channel.renewState == UA_SECURECHANNELRENEWSTATE_SENT ||
792
0
       client->nextChannelRenewal > now)
793
0
        return UA_STATUSCODE_GOODCALLAGAIN;
794
795
0
    UA_StatusCode res = sendOPNAsync(client, true);
796
0
    setConnectStatus(client, res);
797
798
0
    return res;
799
0
}
800
801
UA_StatusCode
802
0
UA_Client_renewSecureChannel(UA_Client *client) {
803
0
    lockClient(client);
804
0
    UA_StatusCode res = __Client_renewSecureChannel(client);
805
0
    unlockClient(client);
806
0
    return res;
807
0
}
808
809
static void
810
responseReadNamespacesArray(UA_Client *client, void *userdata,
811
0
                            UA_UInt32 requestId, void *response) {
812
0
    client->namespacesHandshake = false;
813
0
    client->haveNamespaces = true;
814
815
0
    UA_ReadResponse *resp = (UA_ReadResponse *)response;
816
817
    /* Validate the response before dereferencing results[0]. An
818
     * empty-array encoding yields UA_EMPTY_ARRAY_SENTINEL (0x1, non-NULL),
819
     * bypassing a bare "!resp->results" check. */
820
0
    if(resp->responseHeader.serviceResult != UA_STATUSCODE_GOOD ||
821
0
       resp->resultsSize < 1 ||
822
0
       !resp->results ||
823
0
       !resp->results[0].hasValue ||
824
0
       !resp->results[0].value.data ||
825
0
       resp->results[0].value.data == UA_EMPTY_ARRAY_SENTINEL) {
826
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
827
0
                     "No result in the read namespace array response");
828
0
        return;
829
0
    }
830
0
    if(!UA_Variant_hasArrayType(&resp->results[0].value, &UA_TYPES[UA_TYPES_STRING])) {
831
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
832
0
                     "Read NamespaceArray returned an unexpected type");
833
0
        return;
834
0
    }
835
0
    UA_String *ns = (UA_String *)resp->results[0].value.data;
836
0
    size_t nsSize = resp->results[0].value.arrayLength;
837
0
    if(nsSize < 2) {
838
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
839
0
                     "Read NamespaceArray returned too few entries");
840
0
        return;
841
0
    }
842
0
    UA_String_copy(&ns[1], &client->namespaces[1]);
843
0
    for(size_t i = 2; i < nsSize; ++i) {
844
0
        UA_UInt16 nsIndex = 0;
845
0
        UA_Client_addNamespace(client, ns[i], &nsIndex);
846
0
    }
847
848
    /* Set up the mapping. */
849
0
    UA_NamespaceMapping *nsMapping = (UA_NamespaceMapping*)
850
0
        UA_calloc(1, sizeof(UA_NamespaceMapping));
851
0
    if(!nsMapping) {
852
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
853
0
                     "Namespace mapping creation failed. Out of Memory.");
854
0
        return;
855
0
    }
856
0
    UA_StatusCode retval =
857
0
        UA_Array_copy(client->namespaces, client->namespacesSize,
858
0
                      (void**)&nsMapping->namespaceUris,
859
0
                      &UA_TYPES[UA_TYPES_STRING]);
860
0
    if(retval != UA_STATUSCODE_GOOD) {
861
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
862
0
                     "Failed to copy the namespaces with StatusCode %s.",
863
0
                     UA_StatusCode_name(retval));
864
0
        UA_NamespaceMapping_delete(nsMapping);
865
0
        return;
866
0
    }
867
0
    nsMapping->namespaceUrisSize = client->namespacesSize;
868
869
0
    nsMapping->remote2local = (UA_UInt16*)UA_calloc( nsSize, sizeof(UA_UInt16));
870
0
    if(!nsMapping->remote2local) {
871
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
872
0
                     "Namespace mapping creation failed. Out of Memory.");
873
0
        UA_NamespaceMapping_delete(nsMapping);
874
0
        return;
875
0
    }
876
0
    nsMapping->remote2localSize = nsSize;
877
0
    nsMapping->remote2local[0] = 0;
878
0
    nsMapping->remote2local[1] = 1;
879
880
0
    for(size_t i = 2; i < nsSize; ++i) {
881
0
        UA_UInt16 nsIndex = 0;
882
0
        UA_Client_getNamespaceIndex(client, ns[i], &nsIndex);
883
0
        nsMapping->remote2local[i] = nsIndex;
884
0
    }
885
886
0
    size_t l2rSize = client->namespacesSize > nsSize ? client->namespacesSize : nsSize;
887
0
    nsMapping->local2remote = (UA_UInt16*)UA_calloc(l2rSize, sizeof(UA_UInt16));
888
0
    if(!nsMapping->local2remote) {
889
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
890
0
                     "Namespace mapping creation failed. Out of Memory.");
891
0
        UA_NamespaceMapping_delete(nsMapping);
892
0
        return;
893
0
    }
894
0
    nsMapping->local2remoteSize = l2rSize;
895
0
    nsMapping->local2remote[0] = 0;
896
0
    nsMapping->local2remote[1] = 1;
897
898
0
    for(size_t i = 2; i < nsMapping->remote2localSize; ++i) {
899
0
        UA_UInt16 localIndex = nsMapping->remote2local[i];
900
0
        nsMapping->local2remote[localIndex] = (UA_UInt16)i;
901
0
    }
902
903
0
    client->channel.namespaceMapping = nsMapping;
904
0
}
905
906
/* We read the namespaces right after the session has opened. The user might
907
 * already requests other services in parallel. That leaves a short time where
908
 * requests can be made before the namespace mapping is configured. */
909
static void
910
0
readNamespacesArrayAsync(UA_Client *client) {
911
0
    UA_LOCK_ASSERT(&client->clientMutex);
912
913
    /* Check the connection status */
914
0
    if(client->sessionState != UA_SESSIONSTATE_CREATED &&
915
0
       client->sessionState != UA_SESSIONSTATE_ACTIVATED) {
916
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
917
0
                     "Cannot read the namespaces array, session neither created nor "
918
0
                     "activated. Actual state: '%u'", client->sessionState);
919
0
        return;
920
0
    }
921
922
    /* Set up the read request */
923
0
    UA_ReadRequest rr;
924
0
    UA_ReadRequest_init(&rr);
925
926
0
    UA_ReadValueId nodesToRead;
927
0
    UA_ReadValueId_init(&nodesToRead);
928
0
    nodesToRead.nodeId = UA_NS0ID(SERVER_NAMESPACEARRAY);
929
0
    nodesToRead.attributeId = UA_ATTRIBUTEID_VALUE;
930
931
0
    rr.nodesToRead = &nodesToRead;
932
0
    rr.nodesToReadSize = 1;
933
934
    /* Send the async read request */
935
0
    UA_StatusCode res =
936
0
        __Client_AsyncService(client, &rr, &UA_TYPES[UA_TYPES_READREQUEST],
937
0
                              (UA_ClientAsyncServiceCallback)responseReadNamespacesArray,
938
0
                              &UA_TYPES[UA_TYPES_READRESPONSE],
939
0
                              NULL, NULL);
940
941
0
    if(res == UA_STATUSCODE_GOOD)
942
0
        client->namespacesHandshake = true;
943
0
    else
944
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
945
0
                     "Could not read the namespace array with error code %s",
946
0
                     UA_StatusCode_name(res));
947
0
}
948
949
static void
950
0
extractEphemeralKeyFromAddHeader(UA_Client *client, UA_ExtensionObject *ah) {
951
0
    const UA_DataType *ahType = &UA_TYPES[UA_TYPES_ADDITIONALPARAMETERSTYPE];
952
0
    if(!UA_ExtensionObject_hasDecodedType(ah, ahType))
953
0
        return;
954
955
0
    UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_SESSION,
956
0
                 "Server Ephemeral Key in the response");
957
958
    /* KeyValueMap has the identical structure the UA_AdditionalParametersType */
959
0
    UA_KeyValueMap *map = (UA_KeyValueMap*)ah->content.decoded.data;
960
961
    /* TODO: Handle the ECDHPolicyUri */
962
963
    /* Get the Ephemeral Key */
964
0
    UA_EphemeralKeyType *ephKey = (UA_EphemeralKeyType*)(uintptr_t)
965
0
        UA_KeyValueMap_getScalar(map, UA_QUALIFIEDNAME(0, "ECDHKey"),
966
0
                                 &UA_TYPES[UA_TYPES_EPHEMERALKEYTYPE]);
967
0
    if(!ephKey)
968
0
        return; /* TODO: Security error? */
969
970
    /* Move the Ephemeral Key into the client */
971
0
    UA_ByteString_clear(&client->serverEphemeralPubKey);
972
0
    client->serverEphemeralPubKey = ephKey->publicKey;
973
0
    UA_ByteString_init(&ephKey->publicKey);
974
975
    /* TODO: Validate the signature of the ephemeral key */
976
0
}
977
978
static void
979
responseActivateSession(UA_Client *client, void *userdata,
980
0
                        UA_UInt32 requestId, void *response) {
981
0
    UA_LOCK_ASSERT(&client->clientMutex);
982
983
0
    UA_ActivateSessionResponse *ar = (UA_ActivateSessionResponse*)response;
984
0
    if(ar->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
985
        /* Activating the Session failed */
986
0
        cleanupSession(client);
987
988
        /* Configuration option to not create a new Session */
989
0
        if(client->config.noNewSession) {
990
0
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
991
0
                         "Session cannot be activated with StatusCode %s. "
992
0
                         "The client is configured not to create a new Session.",
993
0
                         UA_StatusCode_name(ar->responseHeader.serviceResult));
994
0
            setConnectStatus(client, ar->responseHeader.serviceResult);
995
0
            return;
996
0
        }
997
998
        /* The Session is no longer usable. Create a brand new one. */
999
0
        if(ar->responseHeader.serviceResult == UA_STATUSCODE_BADSESSIONIDINVALID ||
1000
0
           ar->responseHeader.serviceResult == UA_STATUSCODE_BADSESSIONCLOSED) {
1001
0
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
1002
0
                           "Session to be activated no longer exists. Create a new Session.");
1003
0
            setConnectStatus(client, createSessionAsync(client));
1004
0
            return;
1005
0
        }
1006
1007
        /* Something else is wrong. Maybe the credentials no longer work. Give up. */
1008
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
1009
0
                     "Session cannot be activated with StatusCode %s. "
1010
0
                     "The client cannot recover from this, closing the connection.",
1011
0
                     UA_StatusCode_name(ar->responseHeader.serviceResult));
1012
0
        setConnectStatus(client, ar->responseHeader.serviceResult);
1013
0
        return;
1014
0
    }
1015
1016
    /* Check the (session) nonce length. The session nonce is the application
1017
     * nonce (>= 32 bytes), independent of the SecurityPolicy's SecureChannel
1018
     * nonce length (e.g. the 64-byte ECC ephemeral key). */
1019
0
    if(ar->serverNonce.length < 32) {
1020
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
1021
0
                     "Session cannot be activated with a nonce "
1022
0
                     "that is too short");
1023
0
        setConnectStatus(client, UA_STATUSCODE_BADSECURITYCHECKSFAILED);
1024
0
        return;
1025
0
    }
1026
1027
    /* Replace the nonce */
1028
0
    UA_ByteString_clear(&client->serverSessionNonce);
1029
0
    client->serverSessionNonce = ar->serverNonce;
1030
0
    UA_ByteString_init(&ar->serverNonce);
1031
1032
    /* Extract the server's ECC ephemeral public key from the ActivateSession
1033
     * response */
1034
0
    extractEphemeralKeyFromAddHeader(client, &ar->responseHeader.additionalHeader);
1035
1036
0
    client->sessionState = UA_SESSIONSTATE_ACTIVATED;
1037
0
    notifyClientState(client);
1038
1039
    /* Read the namespaces array if we don't already have it */
1040
0
    if(!client->haveNamespaces)
1041
0
        readNamespacesArrayAsync(client);
1042
1043
    /* Immediately check if publish requests are outstanding - for example when
1044
     * an existing Session has been reattached / activated. */
1045
0
#ifdef UA_ENABLE_SUBSCRIPTIONS
1046
0
    __Client_Subscriptions_backgroundPublish(client);
1047
0
#endif
1048
0
}
1049
1050
static UA_StatusCode
1051
0
activateSessionAsync(UA_Client *client) {
1052
0
    UA_LOCK_ASSERT(&client->clientMutex);
1053
1054
    /* We should not try to activate in the current state */
1055
0
    if(client->sessionState != UA_SESSIONSTATE_CREATED &&
1056
0
       client->sessionState != UA_SESSIONSTATE_ACTIVATED) {
1057
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
1058
0
                     "Can not activate session, session neither created nor activated. "
1059
0
                     "Actual state: '%u'", client->sessionState);
1060
0
        return UA_STATUSCODE_BADSESSIONCLOSED;
1061
0
    }
1062
1063
    /* Select the UserTokenPolicy based on the client configuration and the
1064
     * endpoint information. Also instantiates the UserTokenPolicy if not
1065
     * already there. This can happen when an existing Session is
1066
     * transferred. */
1067
0
    const UA_UserTokenPolicy *utp = NULL;
1068
0
    UA_StatusCode retval = initUserTokenPolicy(client, &utp, "ActivateSession");
1069
0
    if(retval != UA_STATUSCODE_GOOD)
1070
0
        return retval;
1071
1072
    /* Initialize the request */
1073
0
    UA_ActivateSessionRequest request;
1074
0
    UA_ActivateSessionRequest_init(&request);
1075
1076
    /* Set the requested LocaleIds */
1077
0
    if(client->config.sessionLocaleIdsSize && client->config.sessionLocaleIds) {
1078
0
        retval = UA_Array_copy(client->config.sessionLocaleIds,
1079
0
                               client->config.sessionLocaleIdsSize,
1080
0
                               (void **)&request.localeIds, &UA_TYPES[UA_TYPES_LOCALEID]);
1081
0
        if(retval != UA_STATUSCODE_GOOD)
1082
0
            return retval;
1083
0
        request.localeIdsSize = client->config.sessionLocaleIdsSize;
1084
0
    }
1085
1086
    /* Set the User Identity Token. If not defined use an anonymous token. Use
1087
     * the PolicyId from the UserTokenPolicy. All token types have the PolicyId
1088
     * string as the first element. */
1089
0
    UA_AnonymousIdentityToken anonToken;
1090
0
    retval = UA_ExtensionObject_copy(&client->config.userIdentityToken,
1091
0
                                     &request.userIdentityToken);
1092
0
    if(request.userIdentityToken.encoding != UA_EXTENSIONOBJECT_ENCODED_NOBODY) {
1093
0
        UA_String *policyId = (UA_String*)request.userIdentityToken.content.decoded.data;
1094
0
        UA_String_clear(policyId);
1095
0
        retval = UA_String_copy(&utp->policyId, policyId);
1096
0
        if(retval != UA_STATUSCODE_GOOD) {
1097
0
            UA_ActivateSessionRequest_clear(&request);
1098
0
            return retval;
1099
0
        }
1100
0
    } else {
1101
0
        UA_AnonymousIdentityToken_init(&anonToken);
1102
0
        UA_ExtensionObject_setValueNoDelete(&request.userIdentityToken, &anonToken,
1103
0
                                            &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]);
1104
0
        anonToken.policyId = utp->policyId;
1105
0
    }
1106
1107
0
    switch(utp->tokenType) {
1108
0
    case UA_USERTOKENTYPE_ANONYMOUS:
1109
0
        break; /* The anonymous token is not encrypted */
1110
0
    case UA_USERTOKENTYPE_USERNAME:
1111
0
    case UA_USERTOKENTYPE_ISSUEDTOKEN:
1112
        /* Encrypt the UserIdentityToken */
1113
0
        retval = encryptUserIdentityToken(client, &request.userIdentityToken);
1114
0
        break;
1115
0
    case UA_USERTOKENTYPE_CERTIFICATE:
1116
        /* Create the UserTokenSignature */
1117
0
        retval = signUserTokenSignature(client, &request);
1118
0
        break;
1119
0
    default:
1120
0
        retval = UA_STATUSCODE_BADINTERNALERROR;
1121
0
    }
1122
0
    if(retval != UA_STATUSCODE_GOOD) {
1123
0
        UA_ActivateSessionRequest_clear(&request);
1124
0
        return retval;
1125
0
    }
1126
1127
    /* Create the client signature with the SecurityPolicy of the SecureChannel */
1128
0
    UA_SecureChannel *channel = &client->channel;
1129
0
    if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
1130
0
       channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
1131
0
        retval |= signClientSignature(client, &request);
1132
1133
    /* Send the request */
1134
0
    if(UA_LIKELY(retval == UA_STATUSCODE_GOOD))
1135
0
        retval = __Client_AsyncService(client, &request,
1136
0
                                       &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST],
1137
0
                                       (UA_ClientAsyncServiceCallback)responseActivateSession,
1138
0
                                       &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE],
1139
0
                                       NULL, NULL);
1140
1141
    /* On success, advance the session state */
1142
0
    if(retval == UA_STATUSCODE_GOOD)
1143
0
        client->sessionState = UA_SESSIONSTATE_ACTIVATE_REQUESTED;
1144
0
    else
1145
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
1146
0
                     "ActivateSession failed when sending the request with error code %s",
1147
0
                     UA_StatusCode_name(retval));
1148
1149
    /* Clean up */
1150
0
    UA_ActivateSessionRequest_clear(&request);
1151
0
    return retval;
1152
0
}
1153
1154
static const UA_String binaryTransport =
1155
    UA_STRING_STATIC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
1156
1157
/* Find a matching endpoint -- the UserTokenPolicy is matched later */
1158
static UA_Boolean
1159
0
matchEndpoint(UA_Client *client, const UA_EndpointDescription *endpoint, unsigned i) {
1160
    /* Matching ApplicationUri if defined */
1161
0
    if(client->config.applicationUri.length > 0 &&
1162
0
       !UA_String_equal(&client->config.applicationUri,
1163
0
                        &endpoint->server.applicationUri)) {
1164
0
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
1165
0
                    "Endpoint %u: Rejected, the server's ApplicationUri %S "
1166
0
                    "does not match the client configuration", i,
1167
0
                    endpoint->server.applicationUri);
1168
0
        return false;
1169
0
    }
1170
1171
    /* Look out for binary transport endpoints.
1172
     * Note: Siemens returns empty ProfileUrl, we will accept it as binary. */
1173
0
    if(endpoint->transportProfileUri.length != 0 &&
1174
0
       !UA_String_equal(&endpoint->transportProfileUri, &binaryTransport)) {
1175
0
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
1176
0
                    "Endpoint %u: Rejected, the TransportProfileUri %S "
1177
0
                    "is not supported", i, endpoint->transportProfileUri);
1178
0
        return false;
1179
0
    }
1180
1181
    /* Valid SecurityMode? */
1182
0
    if(endpoint->securityMode < 1 || endpoint->securityMode > 3) {
1183
0
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
1184
0
                    "Endpoint %u: Rejected, invalid SecurityMode %u",
1185
0
                    i, (unsigned)endpoint->securityMode);
1186
0
        return false;
1187
0
    }
1188
1189
0
    UA_MessageSecurityMode configuredSM = client->config.securityMode;
1190
0
    if(configuredSM > UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
1191
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
1192
0
                     "Bad SecurityMode set in the client config");
1193
0
        return false;
1194
0
    }
1195
1196
    /* Selected SecurityMode? */
1197
0
    if(configuredSM > 0 && configuredSM != endpoint->securityMode) {
1198
0
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
1199
0
                    "Endpoint %u: Rejected, the SecurityMode %s "
1200
0
                    "does not match the client configuration (%s)",
1201
0
                    i, securityModeNames[endpoint->securityMode],
1202
0
                    securityModeNames[configuredSM]);
1203
0
        return false;
1204
0
    }
1205
1206
    /* Matching SecurityPolicy? */
1207
0
    if(client->config.securityPolicyUri.length > 0 &&
1208
0
       !UA_String_equal(&client->config.securityPolicyUri,
1209
0
                        &endpoint->securityPolicyUri)) {
1210
0
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
1211
0
                    "Endpoint %u: Rejected, the SecurityPolicy %S does not "
1212
0
                    "match the configuration", i, endpoint->securityPolicyUri);
1213
0
        return false;
1214
0
    }
1215
1216
    /* SecurityPolicy available? */
1217
0
    if(!getSecurityPolicy(client, endpoint->securityPolicyUri)) {
1218
0
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
1219
0
                    "Endpoint %u: Rejected, the SecurityPolicy %S not supported",
1220
0
                    i, endpoint->securityPolicyUri);
1221
0
        return false;
1222
0
    }
1223
1224
0
    return true;
1225
0
}
1226
1227
/* Match the policy with the configured user token */
1228
static UA_Boolean
1229
matchUserToken(UA_Client *client,
1230
0
               const UA_UserTokenPolicy *tokenPolicy) {
1231
0
    const UA_DataType *tokenType =
1232
0
        client->config.userIdentityToken.content.decoded.type;
1233
1234
0
    if(tokenPolicy->tokenType == UA_USERTOKENTYPE_ANONYMOUS &&
1235
0
       (tokenType == &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN] || !tokenType))
1236
0
        return true;
1237
1238
0
    if(tokenPolicy->tokenType == UA_USERTOKENTYPE_USERNAME &&
1239
0
       tokenType == &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN])
1240
0
        return true;
1241
1242
0
    if(tokenPolicy->tokenType == UA_USERTOKENTYPE_CERTIFICATE &&
1243
0
       tokenType == &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN])
1244
0
        return true;
1245
1246
0
    if(tokenPolicy->tokenType == UA_USERTOKENTYPE_ISSUEDTOKEN &&
1247
0
       tokenType == &UA_TYPES[UA_TYPES_ISSUEDIDENTITYTOKEN])
1248
0
        return true;
1249
1250
0
    return false;
1251
0
}
1252
1253
static UA_Boolean
1254
matchUserTokenPolicy(UA_Client *client, UA_EndpointDescription *endpoint,
1255
0
                     UA_UserTokenPolicy *utp, char *logPrefix) {
1256
    /* Match with the configured UserToken */
1257
0
    if(!matchUserToken(client, utp)) {
1258
0
        if(logPrefix) {
1259
0
            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
1260
0
                        "%s: UserTokenPolicy %S rejected -- does not match "
1261
0
                        "the type of UserIdentityToken configured in the client",
1262
0
                        logPrefix, utp->policyId);
1263
0
        }
1264
0
        return false;
1265
0
    }
1266
1267
    /* If not defined, use the SecurityPolicy of the SecureChannel */
1268
0
    UA_String tokenPolicyUri =
1269
0
        (UA_String_isEmpty(&utp->securityPolicyUri)) ?
1270
0
        endpoint->securityPolicyUri : utp->securityPolicyUri;
1271
1272
    /* SecurityPolicyUri matches the configuration? */
1273
0
    if(!UA_String_isEmpty(&client->config.authSecurityPolicyUri) &&
1274
0
       !UA_String_equal(&client->config.authSecurityPolicyUri,
1275
0
                        &tokenPolicyUri)) {
1276
0
        if(logPrefix) {
1277
0
            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
1278
0
                        "%s: UserTokenPolicy %S rejected -- uses SecurityPolicy %S, "
1279
0
                        "but the client configuration requires SecurityPolicy %S",
1280
0
                        logPrefix, utp->policyId,
1281
0
                        tokenPolicyUri, client->config.authSecurityPolicyUri);
1282
0
        }
1283
0
        return false;
1284
0
    }
1285
1286
    /* Anoymous authentication */
1287
0
    if(utp->tokenType == UA_USERTOKENTYPE_ANONYMOUS)
1288
0
        return true;
1289
1290
    /* Get the SecurityPolicy for the UserIdentityToken (see
1291
     * initUserTokenPolicy for the authSecurityPolicies/securityPolicies
1292
     * lookup rationale). */
1293
0
    UA_SecurityPolicy *utsp;
1294
0
    if(utp->tokenType == UA_USERTOKENTYPE_CERTIFICATE) {
1295
0
        UA_X509IdentityToken *token = (UA_X509IdentityToken*)
1296
0
            client->config.userIdentityToken.content.decoded.data;
1297
0
        utsp = getAuthSecurityPolicy(client, tokenPolicyUri,
1298
0
                                     &token->certificateData);
1299
0
    } else {
1300
0
        utsp = getAuthSecurityPolicy(client, tokenPolicyUri, NULL);
1301
0
        if(!utsp)
1302
0
            utsp = getSecurityPolicy(client, tokenPolicyUri);
1303
0
    }
1304
0
    if(!utsp) {
1305
0
        if(logPrefix) {
1306
0
            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
1307
0
                        "%s: UserTokenPolicy %S rejected -- the "
1308
0
                        "SecurityPolicy %S is not available",
1309
0
                        logPrefix, utp->policyId, tokenPolicyUri);
1310
0
        }
1311
0
        return false;
1312
0
    }
1313
1314
    /* Check if a secret is transmitted in cleartext */
1315
0
    if(endpoint->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT &&
1316
0
       utsp->policyType == UA_SECURITYPOLICYTYPE_NONE) {
1317
0
        if(!client->config.allowNonePolicyPassword) {
1318
0
            if(logPrefix) {
1319
0
                UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
1320
0
                            "%s: UserTokenPolicy %S rejected -- the "
1321
0
                            "AuthenticationToken must not be transmitted "
1322
0
                            "without encryption (override with"
1323
0
                            "allowNonePolicyPassword setting)",
1324
0
                            logPrefix, utp->policyId);
1325
0
            }
1326
0
            return false;
1327
0
        }
1328
0
    }
1329
1330
    /* Found a match */
1331
0
    return true;
1332
0
}
1333
1334
/* Returns a matching UserTokenPolicy from the EndpointDescription. If a
1335
 * UserTokenPolicy is configured in the client config, then we need an exact
1336
 * match. */
1337
static UA_UserTokenPolicy *
1338
findUserTokenPolicy(UA_Client *client, UA_EndpointDescription *endpoint,
1339
0
                    char *logPrefix) {
1340
    /* Was a UserTokenPolicy configured? Then we need an exact match. */
1341
0
    UA_UserTokenPolicy *requiredTokenPolicy = NULL;
1342
0
    UA_UserTokenPolicy tmp;
1343
0
    UA_UserTokenPolicy_init(&tmp);
1344
0
    if(!UA_equal(&tmp, &client->config.userTokenPolicy,
1345
0
                 &UA_TYPES[UA_TYPES_USERTOKENPOLICY]))
1346
0
        requiredTokenPolicy = &client->config.userTokenPolicy;
1347
1348
    /* Return the first UserTokenPolicy matching the config */
1349
0
    for(size_t j = 0; j < endpoint->userIdentityTokensSize; ++j) {
1350
0
        UA_UserTokenPolicy *tokenPolicy = &endpoint->userIdentityTokens[j];
1351
1352
        /* Need the extact configured policy */
1353
0
        if(requiredTokenPolicy &&
1354
0
           !UA_equal(requiredTokenPolicy, tokenPolicy,
1355
0
                     &UA_TYPES[UA_TYPES_USERTOKENPOLICY])) {
1356
0
            if(logPrefix) {
1357
0
                UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
1358
0
                            "%s: UserTokenPolicy %S rejected -- a different "
1359
0
                            "UserTokenPolicy %S is specified in the client config",
1360
0
                            logPrefix, tokenPolicy->policyId,
1361
0
                            requiredTokenPolicy->policyId);
1362
0
            }
1363
0
            continue;
1364
0
        }
1365
1366
        /* Match with the client configured */
1367
0
        if(matchUserTokenPolicy(client, endpoint, tokenPolicy, logPrefix))
1368
0
            return tokenPolicy;
1369
0
    }
1370
1371
0
    return NULL;
1372
0
}
1373
1374
/* Combination of UA_Client_getEndpointsInternal and getEndpoints */
1375
static void
1376
responseGetEndpoints(UA_Client *client, void *userdata,
1377
0
                     UA_UInt32 requestId, void *response) {
1378
0
    UA_LOCK_ASSERT(&client->clientMutex);
1379
1380
0
    client->endpointsHandshake = false;
1381
1382
0
    UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
1383
0
                 "Received GetEndpointsResponse");
1384
1385
0
    UA_GetEndpointsResponse *resp = (UA_GetEndpointsResponse*)response;
1386
1387
    /* GetEndpoints not possible. Fail the connection */
1388
0
    if(resp->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
1389
        /* Fail the connection attempt if the SecureChannel is still connected.
1390
         * If the SecureChannel is (intentionally or unintentionally) closed,
1391
         * the connectStatus should come from there. */
1392
0
        if(UA_SecureChannel_isConnected(&client->channel)) {
1393
0
           UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
1394
0
                        "GetEndpointRequest failed with error code %s",
1395
0
                        UA_StatusCode_name(resp->responseHeader.serviceResult));
1396
0
           setConnectStatus(client, resp->responseHeader.serviceResult);
1397
0
        }
1398
1399
0
        UA_GetEndpointsResponse_clear(resp);
1400
0
        return;
1401
0
    }
1402
1403
    /* Warn if the Endpoints look incomplete / don't match the EndpointUrl */
1404
0
    Client_warnEndpointsResult(client, resp, &client->discoveryUrl);
1405
1406
0
    const size_t notFound = (size_t)-1;
1407
0
    size_t bestEndpointIndex = notFound;
1408
0
    UA_Byte bestEndpointLevel = 0;
1409
0
    UA_UserTokenPolicy *utp = NULL;
1410
1411
    /* Find a matching combination of Endpoint and UserTokenPolicy */
1412
0
    for(size_t i = 0; i < resp->endpointsSize; ++i) {
1413
0
        UA_EndpointDescription* endpoint = &resp->endpoints[i];
1414
1415
        /* Do we already have a better candidate? */
1416
0
        if(endpoint->securityLevel < bestEndpointLevel) {
1417
0
            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
1418
0
                        "Endpoint %u: Rejected, better SecurityLevel found before",
1419
0
                        (unsigned)i);
1420
0
            continue;
1421
0
        }
1422
1423
        /* Does the endpoint match the client configuration? */
1424
0
        if(!matchEndpoint(client, endpoint, (unsigned)i))
1425
0
            continue;
1426
1427
        /* Do we want a session? If yes, then the endpoint needs to have a
1428
         * UserTokenPolicy that matches the configuration. */
1429
0
        if(!client->config.noSession) {
1430
0
            char logPrefix[32];
1431
0
            mp_snprintf(logPrefix, 32, "Endpoint %u", (unsigned)i);
1432
0
            utp = findUserTokenPolicy(client, endpoint, logPrefix);
1433
0
            if(!utp) {
1434
0
                UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
1435
0
                            "Endpoint %u: Rejected, no matching UserTokenPolicy",
1436
0
                            (unsigned)i);
1437
0
                continue;
1438
0
            }
1439
0
        }
1440
1441
        /* Best endpoint so far */
1442
0
        bestEndpointLevel = endpoint->securityLevel;
1443
0
        bestEndpointIndex = i;
1444
0
        if(utp) {
1445
0
            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
1446
0
                        "Endpoint %u: Best endpoint so far with "
1447
0
                        "UserTokenPolicy %S", (unsigned)i, utp->policyId);
1448
0
        } else {
1449
0
            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
1450
0
                        "Endpoint %u: Best endpoint so far", (unsigned)i);
1451
0
        }
1452
0
    }
1453
1454
    /* No matching endpoint found */
1455
0
    if(bestEndpointIndex == notFound) {
1456
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
1457
0
                     "No suitable endpoint found");
1458
0
        setConnectStatus(client, UA_STATUSCODE_BADIDENTITYTOKENREJECTED);
1459
0
        return;
1460
0
    }
1461
1462
    /* Store the endpoint description in the client. It contains the
1463
     * ApplicationDescription and the UserTokenPolicies. We continue to look up
1464
     * the matching UserTokenPolicy from there. */
1465
0
    UA_EndpointDescription_clear(&client->endpoint);
1466
0
    client->endpoint = resp->endpoints[bestEndpointIndex];
1467
0
    UA_EndpointDescription_init(&resp->endpoints[bestEndpointIndex]);
1468
1469
0
    if(utp) {
1470
0
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
1471
0
                    "Endpoint %u selected with SecurityMode "
1472
0
                    "%s, SecurityPolicy %S and UserTokenPolicy %S",
1473
0
                    bestEndpointIndex,
1474
0
                    securityModeNames[client->endpoint.securityMode],
1475
0
                    client->endpoint.securityPolicyUri,
1476
0
                    utp->policyId);
1477
0
    } else {
1478
0
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
1479
0
                    "Endpoint %u selected with SecurityMode "
1480
0
                    "%s and SecurityPolicy %S", bestEndpointIndex,
1481
0
                    securityModeNames[client->endpoint.securityMode],
1482
0
                    client->endpoint.securityPolicyUri);
1483
0
    }
1484
1485
    /* A different SecurityMode or SecurityPolicy is defined by the Endpoint.
1486
     * Close the SecureChannel and reconnect. */
1487
0
    UA_SecurityPolicy *sp = client->channel.securityPolicy;
1488
0
    if(client->endpoint.securityMode != client->channel.securityMode ||
1489
0
       !UA_String_equal(&client->endpoint.securityPolicyUri, &sp->policyUri)) {
1490
0
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
1491
0
                    "A different SecurityMode or SecurityPolicy is defined "
1492
0
                    "by the selected Endpoint. Close the SecureChannel "
1493
0
                    "and reconnect.");
1494
0
        closeSecureChannel(client);
1495
0
        return;
1496
0
    }
1497
1498
    /* We were using a distinct discovery URL and we are switching away from it.
1499
     * Close the SecureChannel to reopen with the EndpointUrl. If an endpoint
1500
     * was selected, then we use the endpointUrl for the HEL message. */
1501
0
    if(client->discoveryUrl.length > 0 &&
1502
0
       !UA_String_equal(&client->discoveryUrl, &client->endpoint.endpointUrl)) {
1503
0
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
1504
0
                    "The selected endpoint defines an EndpointUrl %S different "
1505
0
                    "from the Url %S used to connect before calling "
1506
0
                    "GetEndpoints. Close the SecureChannel and reconnect with "
1507
0
                    "the new EndpointUrl to ensure the Endpoint is available.",
1508
0
                    client->discoveryUrl, client->endpoint.endpointUrl);
1509
0
        closeSecureChannel(client);
1510
0
        return;
1511
0
    }
1512
1513
    /* We have selected an endpoint that we can use to open a Session on the
1514
     * current SecureChannel. The remote certificate was validated during
1515
     * processing of the OPN response. But if client->endpoint.serverCertificate
1516
     * is empty we do not compare against the expectation from the endpoint. */
1517
1518
    /* Is the same certificate used for the SecureChannel and the selected
1519
     * endpoint?
1520
     *
1521
     * Both the clientCertificate of this request and the remoteCertificate of
1522
     * the channel may contain a partial or a complete certificate chain. The
1523
     * compareCertificate function will compare the first certificate of each
1524
     * chain. The end certificate shall be located first in the chain according
1525
     * to the OPC UA specification Part 6 (1.04), chapter 6.2.3.*/
1526
0
    if(client->channel.securityMode != UA_MESSAGESECURITYMODE_NONE) {
1527
0
        void *cc = client->channel.channelContext;
1528
0
        UA_StatusCode res = sp->compareCertificate(sp, cc,
1529
0
                                                   &client->endpoint.serverCertificate);
1530
0
        if(res != UA_STATUSCODE_GOOD) {
1531
0
            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
1532
0
                        "The selected endpoint defines a different server certificate "
1533
0
                        "from then one used by the server for the initial SecureChannel "
1534
0
                        "(to call GetEndpoints). Close the SecureChannel and reconnect.");
1535
0
            closeSecureChannel(client);
1536
0
            return;
1537
0
        }
1538
0
    }
1539
1540
    /* Continue with the current SecureChannel */
1541
0
}
1542
1543
static UA_StatusCode
1544
0
requestGetEndpoints(UA_Client *client) {
1545
0
    UA_LOCK_ASSERT(&client->clientMutex);
1546
1547
0
    UA_GetEndpointsRequest request;
1548
0
    UA_GetEndpointsRequest_init(&request);
1549
0
    request.endpointUrl = getEndpointUrl(client);
1550
1551
0
    UA_StatusCode retval =
1552
0
        __Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST],
1553
0
                              (UA_ClientAsyncServiceCallback) responseGetEndpoints,
1554
0
                              &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE], NULL, NULL);
1555
0
    if(retval != UA_STATUSCODE_GOOD) {
1556
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
1557
0
                     "RequestGetEndpoints failed when sending the request with error code %s",
1558
0
                     UA_StatusCode_name(retval));
1559
0
        return retval;
1560
0
    }
1561
1562
0
    client->endpointsHandshake = true;
1563
0
    return UA_STATUSCODE_GOOD;
1564
0
}
1565
1566
static void
1567
responseFindServers(UA_Client *client, void *userdata,
1568
0
                    UA_UInt32 requestId, void *response) {
1569
0
    client->findServersHandshake = false;
1570
0
    UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
1571
0
                 "Received FindServersResponse");
1572
1573
    /* Error handling. Log the error but continue to connect with the current
1574
     * EndpointURL. */
1575
0
    UA_FindServersResponse *fsr = (UA_FindServersResponse*)response;
1576
0
    if(fsr->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
1577
0
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
1578
0
                       "FindServers failed with error code %s. Continue with the "
1579
0
                       "EndpointURL %S.",
1580
0
                       UA_StatusCode_name(fsr->responseHeader.serviceResult),
1581
0
                       client->config.endpointUrl);
1582
0
        UA_String_clear(&client->discoveryUrl);
1583
0
        UA_String_copy(&client->config.endpointUrl, &client->discoveryUrl);
1584
0
        return;
1585
0
    }
1586
1587
    /* Check if one of the returned servers matches the EndpointURL already used */
1588
0
    for(size_t i = 0; i < fsr->serversSize; i++) {
1589
0
        UA_ApplicationDescription *server = &fsr->servers[i];
1590
1591
        /* Filter by the ApplicationUri if defined */
1592
0
        if(client->config.applicationUri.length > 0 &&
1593
0
           !UA_String_equal(&client->config.applicationUri, &server->applicationUri))
1594
0
            continue;
1595
1596
0
        for(size_t j = 0; j < server->discoveryUrlsSize; j++) {
1597
0
            if(UA_String_equal(&client->config.endpointUrl, &server->discoveryUrls[j])) {
1598
0
                UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
1599
0
                            "The initially defined EndpointURL %S "
1600
0
                            "is valid for the server", client->config.endpointUrl);
1601
0
                UA_String_clear(&client->discoveryUrl);
1602
0
                client->discoveryUrl = server->discoveryUrls[j];
1603
0
                UA_String_init(&server->discoveryUrls[j]);
1604
0
                return;
1605
0
            }
1606
0
        }
1607
0
    }
1608
1609
    /* The current EndpointURL is not usable. Pick the first "opc.tcp" DiscoveryUrl of a
1610
     * returned server. */
1611
0
    for(size_t i = 0; i < fsr->serversSize; i++) {
1612
0
        UA_ApplicationDescription *server = &fsr->servers[i];
1613
0
        if(server->applicationType != UA_APPLICATIONTYPE_SERVER &&
1614
0
            server->applicationType != UA_APPLICATIONTYPE_CLIENTANDSERVER &&
1615
0
            server->applicationType != UA_APPLICATIONTYPE_DISCOVERYSERVER)
1616
0
            continue;
1617
1618
        /* Filter by the ApplicationUri if defined */
1619
0
        if(client->config.applicationUri.length > 0 &&
1620
0
           !UA_String_equal(&client->config.applicationUri, &server->applicationUri))
1621
0
            continue;
1622
1623
0
        for(size_t j = 0; j < server->discoveryUrlsSize; j++) {
1624
            /* Try to parse the DiscoveryUrl. This weeds out http schemas (etc.)
1625
             * and invalid DiscoveryUrls in general. */
1626
0
            UA_String hostname, path;
1627
0
            UA_UInt16 port;
1628
0
            UA_StatusCode res =
1629
0
                UA_parseEndpointUrl(&server->discoveryUrls[j], &hostname, &port, &path);
1630
0
            if(res != UA_STATUSCODE_GOOD)
1631
0
                continue;
1632
1633
            /* Use this DiscoveryUrl in the client */
1634
0
            UA_String_clear(&client->discoveryUrl);
1635
0
            client->discoveryUrl = server->discoveryUrls[j];
1636
0
            UA_String_init(&server->discoveryUrls[j]);
1637
1638
0
            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
1639
0
                        "Use the EndpointURL %S returned from FindServers and reconnect",
1640
0
                        client->discoveryUrl);
1641
1642
            /* Close the SecureChannel to build it up new with the correct
1643
             * EndpointURL in the HEL/ACK handshake. In closeSecureChannel the
1644
             * received client->endpoint is reset also. */
1645
0
            closeSecureChannel(client);
1646
0
            return;
1647
0
        }
1648
0
    }
1649
1650
    /* Could not find a suitable server. Try to continue with the
1651
     * original EndpointURL. */
1652
0
    UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
1653
0
                   "FindServers did not returned a suitable DiscoveryURL. "
1654
0
                   "Continue with the EndpointURL %S.", client->config.endpointUrl);
1655
0
    UA_String_clear(&client->discoveryUrl);
1656
0
    UA_String_copy(&client->config.endpointUrl, &client->discoveryUrl);
1657
0
}
1658
1659
static UA_StatusCode
1660
0
requestFindServers(UA_Client *client) {
1661
0
    UA_FindServersRequest request;
1662
0
    UA_FindServersRequest_init(&request);
1663
0
    request.requestHeader.timeoutHint = 10000;
1664
0
    request.endpointUrl = client->config.endpointUrl;
1665
0
    UA_StatusCode retval =
1666
0
        __Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_FINDSERVERSREQUEST],
1667
0
                              (UA_ClientAsyncServiceCallback) responseFindServers,
1668
0
                              &UA_TYPES[UA_TYPES_FINDSERVERSRESPONSE], NULL, NULL);
1669
0
    if(retval != UA_STATUSCODE_GOOD) {
1670
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
1671
0
                     "FindServers failed when sending the request with error code %s",
1672
0
                     UA_StatusCode_name(retval));
1673
0
        return retval;
1674
0
    }
1675
1676
0
    client->findServersHandshake = true;
1677
0
    return UA_STATUSCODE_GOOD;
1678
0
}
1679
1680
static void
1681
createSessionCallback(UA_Client *client, void *userdata,
1682
0
                      UA_UInt32 requestId, void *response) {
1683
0
    UA_LOCK_ASSERT(&client->clientMutex);
1684
1685
0
    UA_CreateSessionResponse *csr = (UA_CreateSessionResponse*)response;
1686
0
    UA_StatusCode res = csr->responseHeader.serviceResult;
1687
0
    if(res != UA_STATUSCODE_GOOD)
1688
0
        goto cleanup;
1689
1690
0
    if(client->channel.securityMode == UA_MESSAGESECURITYMODE_SIGN ||
1691
0
       client->channel.securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
1692
        /* Verify the session response was created with the same certificate as
1693
         * the SecureChannel */
1694
0
        if(!UA_ByteString_equal(&csr->serverCertificate,
1695
0
                                &client->channel.remoteCertificate)) {
1696
0
            res = UA_STATUSCODE_BADCERTIFICATEINVALID;
1697
0
            goto cleanup;
1698
0
        }
1699
1700
        /* Verify the client signature */
1701
0
        res = checkCreateSessionSignature(client, &client->channel, csr);
1702
0
        if(res != UA_STATUSCODE_GOOD)
1703
0
            goto cleanup;
1704
0
    }
1705
1706
    /* Copy the SessionId */
1707
0
    UA_NodeId_clear(&client->sessionId);
1708
0
    res |= UA_NodeId_copy(&csr->sessionId, &client->sessionId);
1709
1710
    /* Check the (session) nonce length. The session nonce is the application
1711
     * nonce (>= 32 bytes), independent of the SecurityPolicy's SecureChannel
1712
     * nonce length (e.g. the 64-byte ECC ephemeral key). */
1713
0
    if(csr->serverNonce.length < 32) {
1714
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
1715
0
                     "Session cannot be created with a nonce "
1716
0
                     "that is too short");
1717
0
        res = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1718
0
        goto cleanup;
1719
0
    }
1720
1721
    /* Copy nonce and AuthenticationToken */
1722
0
    UA_ByteString_clear(&client->serverSessionNonce);
1723
0
    UA_NodeId_clear(&client->authenticationToken);
1724
0
    res |= UA_ByteString_copy(&csr->serverNonce, &client->serverSessionNonce);
1725
0
    res |= UA_NodeId_copy(&csr->authenticationToken, &client->authenticationToken);
1726
0
    if(res != UA_STATUSCODE_GOOD)
1727
0
        goto cleanup;
1728
1729
    /* Extract the server's ECC ephemeral public key from the CreateSession
1730
     * response */
1731
0
    extractEphemeralKeyFromAddHeader(client, &csr->responseHeader.additionalHeader);
1732
1733
    /* Activate the new Session */
1734
0
    client->sessionState = UA_SESSIONSTATE_CREATED;
1735
1736
0
 cleanup:
1737
0
    setConnectStatus(client, res);
1738
0
    if(client->connectStatus != UA_STATUSCODE_GOOD)
1739
0
        client->sessionState = UA_SESSIONSTATE_CLOSED;
1740
0
}
1741
1742
/* OPC UA Part 6 ECC: request an ephemeral ECDH key from the server by adding an
1743
 * "ECDHPolicyUri" entry (value = the user-token SecurityPolicy URI) to the
1744
 * request's AdditionalHeader. The server returns its ephemeral public key under
1745
 * "ECDHKey" in the response AdditionalHeader, which the client needs to encrypt
1746
 * an ECC UserIdentityToken. For non-ECC user-token policies this is a no-op.
1747
 * The caller must clear the AdditionalHeader after sending. */
1748
static UA_StatusCode
1749
0
requestServerEphemeralKey(UA_Client *client, UA_RequestHeader *rh) {
1750
0
    UA_SecurityPolicy *utpSp = client->utpSp;
1751
0
    if(!UA_SecurityPolicy_isEcc(utpSp))
1752
0
        return UA_STATUSCODE_GOOD;
1753
1754
0
    UA_AdditionalParametersType *ap = UA_AdditionalParametersType_new();
1755
0
    if(!ap)
1756
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
1757
0
    ap->parameters = (UA_KeyValuePair*)
1758
0
        UA_Array_new(1, &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
1759
0
    if(!ap->parameters) {
1760
0
        UA_AdditionalParametersType_delete(ap);
1761
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
1762
0
    }
1763
0
    ap->parametersSize = 1;
1764
0
    ap->parameters[0].key = UA_QUALIFIEDNAME_ALLOC(0, "ECDHPolicyUri");
1765
0
    UA_StatusCode res =
1766
0
        UA_Variant_setScalarCopy(&ap->parameters[0].value, &utpSp->policyUri,
1767
0
                                 &UA_TYPES[UA_TYPES_STRING]);
1768
0
    if(res != UA_STATUSCODE_GOOD) {
1769
0
        UA_AdditionalParametersType_delete(ap);
1770
0
        return res;
1771
0
    }
1772
0
    UA_ExtensionObject_setValue(&rh->additionalHeader, ap,
1773
0
                                &UA_TYPES[UA_TYPES_ADDITIONALPARAMETERSTYPE]);
1774
0
    return UA_STATUSCODE_GOOD;
1775
0
}
1776
1777
static UA_StatusCode
1778
0
createSessionAsync(UA_Client *client) {
1779
0
    UA_LOCK_ASSERT(&client->clientMutex);
1780
1781
    /* Select the UserTokenPolicy based on the client configuration and the
1782
     * endpoint information. Also instantiates the UserTokenPolicy if not
1783
     * already there. */
1784
0
    const UA_UserTokenPolicy *utp = NULL;
1785
0
    UA_StatusCode res = initUserTokenPolicy(client, &utp, "CreateSession");
1786
0
    if(res != UA_STATUSCODE_GOOD)
1787
0
        return res;
1788
0
    (void)utp;
1789
1790
    /* Create the CreateSession ClientNonce: a 32-byte random nonce when the
1791
     * SecureChannel is secured. For ECC SecurityPolicies the ClientNonce is
1792
     * NOT the session ephemeral key — the ephemeral keys are exchanged
1793
     * separately (the server's arrives in the response AdditionalHeader; the
1794
     * client's, when needed for UserIdentityToken encryption, is carried in
1795
     * the EccEncryptedSecret). Sending the ephemeral key as the nonce is
1796
     * rejected by conformant servers with BadNonceInvalid. */
1797
0
    UA_SecurityPolicy *sp = client->channel.securityPolicy;
1798
0
    if(sp && client->channel.securityMode != UA_MESSAGESECURITYMODE_NONE) {
1799
0
        size_t nonceLength = 32;
1800
0
        if(client->clientSessionNonce.length != nonceLength) {
1801
0
            UA_ByteString_clear(&client->clientSessionNonce);
1802
0
            res = UA_ByteString_allocBuffer(&client->clientSessionNonce, nonceLength);
1803
0
            if(res != UA_STATUSCODE_GOOD)
1804
0
                return res;
1805
0
        }
1806
        /* Ensure data[0] is not the 'e' of the "eph" ECC ephemeral-key
1807
         * trigger, so generateNonce produces plain random data. */
1808
0
        client->clientSessionNonce.data[0] = 0;
1809
0
        res = sp->generateNonce(sp, client->channel.channelContext,
1810
0
                                &client->clientSessionNonce);
1811
0
        if(res != UA_STATUSCODE_GOOD) {
1812
0
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
1813
0
                         "CreateSession could not create the client nonce");
1814
0
            return res;
1815
0
        }
1816
0
    }
1817
1818
    /* Prepare the request */
1819
0
    UA_CreateSessionRequest request;
1820
0
    UA_CreateSessionRequest_init(&request);
1821
0
    request.clientNonce = client->clientSessionNonce;
1822
0
    request.requestedSessionTimeout = client->config.requestedSessionTimeout;
1823
0
    request.maxResponseMessageSize = UA_INT32_MAX;
1824
0
    request.endpointUrl = client->endpoint.endpointUrl;
1825
0
    request.clientDescription = client->config.clientDescription;
1826
0
    request.sessionName = client->config.sessionName;
1827
1828
    /* Send the certificate that is used for the UserIdentiyToken as the
1829
     * ApplicationCertificate. (sp == client->channel.securityPolicy; guarded
1830
     * so static analysis sees it cannot be a NULL dereference.) */
1831
0
    if(sp)
1832
0
        request.clientCertificate = sp->localCertificate;
1833
1834
    /* For ECC policies, request the server's ephemeral ECDH key (needed to
1835
     * encrypt the UserIdentityToken in ActivateSession). */
1836
0
    res = requestServerEphemeralKey(client, &request.requestHeader);
1837
0
    if(res != UA_STATUSCODE_GOOD)
1838
0
        return res;
1839
1840
    /* Send the request */
1841
0
    res = __Client_AsyncService(client, &request,
1842
0
                                &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST],
1843
0
                                (UA_ClientAsyncServiceCallback)createSessionCallback,
1844
0
                                &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE], NULL, NULL);
1845
1846
    /* The request is encoded+sent synchronously; release the AdditionalHeader. */
1847
0
    UA_ExtensionObject_clear(&request.requestHeader.additionalHeader);
1848
1849
0
    if(res == UA_STATUSCODE_GOOD)
1850
0
        client->sessionState = UA_SESSIONSTATE_CREATE_REQUESTED;
1851
0
    else
1852
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
1853
0
                     "CreateSession failed when sending the request with "
1854
0
                     "error code %s", UA_StatusCode_name(res));
1855
1856
0
    return res;
1857
0
}
1858
1859
static UA_StatusCode
1860
0
initSecurityPolicy(UA_Client *client) {
1861
    /* Find the SecurityPolicy. Use #None if the endpoint is not (yet)
1862
     * configured. */
1863
0
    UA_String secPolicyUri = client->endpoint.securityPolicyUri;
1864
0
    if(secPolicyUri.length == 0)
1865
0
        secPolicyUri = UA_SECURITY_POLICY_NONE_URI;
1866
0
    UA_SecurityPolicy *sp = getSecurityPolicy(client, secPolicyUri);
1867
1868
    /* Unknown SecurityPolicy */
1869
0
    if(!sp) {
1870
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
1871
0
                     "SecurityPolicy %S not available", secPolicyUri);
1872
0
        return UA_STATUSCODE_BADINTERNALERROR;
1873
0
    }
1874
1875
    /* Already initialized -- check we are using the same SecurityPolicy */
1876
0
    if(client->channel.securityPolicy)
1877
0
        return (client->channel.securityPolicy == sp) ?
1878
0
            UA_STATUSCODE_GOOD : UA_STATUSCODE_BADINTERNALERROR;
1879
1880
    /* Verify the remote server certificate */
1881
0
    UA_StatusCode res;
1882
0
    if(client->endpoint.serverCertificate.length > 0) {
1883
0
        res = client->config.certificateVerification.
1884
0
            verifyCertificate(&client->config.certificateVerification,
1885
0
                              &client->endpoint.serverCertificate);
1886
0
        if(res != UA_STATUSCODE_GOOD) {
1887
0
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
1888
0
                         "Cannot validate the server certificate "
1889
0
                         "defined for the selected endpoint");
1890
0
            return res;
1891
0
        }
1892
0
    }
1893
1894
    /* If the sender provides a chain of certificates then we shall extract the
1895
     * ApplicationInstanceCertificate and ignore the extra bytes. See also: OPC
1896
     * UA Part 6, V1.04, 6.7.2.3 Security Header, Table 42 - Asymmetric
1897
     * algorithm Security header */
1898
0
    UA_ByteString appInstCert =
1899
0
        getLeafCertificate(client->endpoint.serverCertificate);
1900
1901
    /* Instantiate the SecurityPolicy context with the remote certificate */
1902
0
    res = UA_SecureChannel_setSecurityPolicy(&client->channel, sp, &appInstCert);
1903
0
    if(res != UA_STATUSCODE_GOOD) {
1904
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
1905
0
                     "Cannot instantiate the SecurityPolicy %S "
1906
0
                     "with the supplied server certificate", sp->policyUri);
1907
0
        return res;
1908
0
    }
1909
1910
    /* Set the SecurityMode. Replace INVALID with NONE as a workaround for
1911
     * misconfigured endpoints. */
1912
0
    UA_MessageSecurityMode securityMode = client->endpoint.securityMode;
1913
0
    if(securityMode == UA_MESSAGESECURITYMODE_INVALID)
1914
0
        securityMode = UA_MESSAGESECURITYMODE_NONE;
1915
0
    res = UA_SecureChannel_setSecurityMode(&client->channel, securityMode);
1916
0
    if(res != UA_STATUSCODE_GOOD) {
1917
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
1918
0
                     "Client configuration uses mismatching "
1919
0
                     "MessageSecurityMode==%u for SecurityPolicy %S",
1920
0
                     securityMode, sp->policyUri);
1921
0
    }
1922
0
    return res;
1923
0
}
1924
1925
static void
1926
0
connectActivity(UA_Client *client) {
1927
0
    UA_LOCK_ASSERT(&client->clientMutex);
1928
0
    UA_LOG_TRACE(client->config.logging, UA_LOGCATEGORY_CLIENT,
1929
0
                 "Client connect iterate");
1930
1931
    /* Could not connect with an error that canot be recovered from */
1932
0
    if(client->connectStatus != UA_STATUSCODE_GOOD)
1933
0
        return;
1934
1935
    /* Already connected */
1936
0
    if(client->sessionState == UA_SESSIONSTATE_ACTIVATED)
1937
0
        return;
1938
1939
    /* Switch on the SecureChannel state */
1940
0
    switch(client->channel.state) {
1941
        /* Nothing to do if the connection has not opened fully */
1942
0
    case UA_SECURECHANNELSTATE_CONNECTING:
1943
0
    case UA_SECURECHANNELSTATE_REVERSE_CONNECTED:
1944
0
    case UA_SECURECHANNELSTATE_CLOSING:
1945
0
    case UA_SECURECHANNELSTATE_HEL_SENT:
1946
0
    case UA_SECURECHANNELSTATE_OPN_SENT:
1947
0
        return;
1948
1949
        /* Send HEL */
1950
0
    case UA_SECURECHANNELSTATE_CONNECTED:
1951
0
        setConnectStatus(client, sendHELMessage(client));
1952
0
        return;
1953
1954
        /* ACK receieved. Send OPN. */
1955
0
    case UA_SECURECHANNELSTATE_ACK_RECEIVED:
1956
0
        setConnectStatus(client, sendOPNAsync(client, false)); /* Send OPN */
1957
0
        return;
1958
1959
        /* The channel is open -> continue with the Session handling */
1960
0
    case UA_SECURECHANNELSTATE_OPEN:
1961
0
        break;
1962
1963
        /* The connection is closed. Reset the SecureChannel and open a new TCP
1964
         * connection */
1965
0
    case UA_SECURECHANNELSTATE_CLOSED:
1966
0
        if(client->config.noReconnect)
1967
0
            setConnectStatus(client, UA_STATUSCODE_BADNOTCONNECTED);
1968
0
        else
1969
0
            initConnect(client); /* Sets the connectStatus internally */
1970
0
        return;
1971
1972
        /* These states should never occur for the client */
1973
0
    default:
1974
0
        setConnectStatus(client, UA_STATUSCODE_BADINTERNALERROR);
1975
0
        return;
1976
0
    }
1977
1978
    /* <-- The SecureChannel is open --> */
1979
1980
    /* Ongoing handshake -> Waiting for a response */
1981
0
    if(client->endpointsHandshake || client->findServersHandshake ||
1982
0
       client->namespacesHandshake)
1983
0
        return;
1984
1985
    /* Call FindServers to see if we should reconnect with another EndpointUrl.
1986
     * This needs to be done before GetEndpoints, as the set of returned
1987
     * endpoints may depend on the EndpointUrl used during the initial HEL/ACK
1988
     * handshake. */
1989
0
    if(client->discoveryUrl.length == 0) {
1990
0
        setConnectStatus(client, requestFindServers(client));
1991
0
        return;
1992
0
    }
1993
1994
    /* GetEndpoints to identify the remote side and/or reset the SecureChannel
1995
     * with encryption */
1996
0
    if(endpointUnconfigured(&client->endpoint)) {
1997
0
        setConnectStatus(client, requestGetEndpoints(client));
1998
0
        return;
1999
0
    }
2000
2001
    /* Have the final SecureChannel but no session */
2002
0
    if(client->config.noSession)
2003
0
        return;
2004
2005
    /* Create and Activate the Session */
2006
0
    switch(client->sessionState) {
2007
        /* Send a CreateSessionRequest */
2008
0
    case UA_SESSIONSTATE_CLOSED:
2009
0
        setConnectStatus(client, createSessionAsync(client));
2010
0
        return;
2011
2012
        /* Activate the Session */
2013
0
    case UA_SESSIONSTATE_CREATED:
2014
0
        setConnectStatus(client, activateSessionAsync(client));
2015
0
        return;
2016
2017
0
    case UA_SESSIONSTATE_CREATE_REQUESTED:
2018
0
    case UA_SESSIONSTATE_ACTIVATE_REQUESTED:
2019
0
    case UA_SESSIONSTATE_ACTIVATED:
2020
0
    case UA_SESSIONSTATE_CLOSING:
2021
0
        return; /* Nothing to do */
2022
2023
        /* These states should never occur for the client */
2024
0
    default:
2025
0
        setConnectStatus(client, UA_STATUSCODE_BADINTERNALERROR);
2026
0
        break;
2027
0
    }
2028
0
}
2029
2030
/* Verify the OPN response. Note that the client knows the remote server
2031
 * certificate before opening the SecureChannel (from the EndpointDescription).
2032
 *
2033
 * The server certificate is used to initialize the SecureChannel/SecurityPolicy
2034
 * before connecting in initSecurityPolicy. The certificate from the endpoint is
2035
 * checked to be the same used in the AsymHeader. */
2036
static UA_StatusCode
2037
verifyClientSecureChannelHeader(void *application, UA_SecureChannel *channel,
2038
0
                                const UA_AsymmetricAlgorithmSecurityHeader *asymHeader) {
2039
0
    UA_Client *client = (UA_Client*)application;
2040
0
    const UA_SecurityPolicy *sp = channel->securityPolicy;
2041
0
    UA_assert(sp != NULL);
2042
2043
    /* Check the SecurityPolicyUri if it is defined. If the SecurityMode is not
2044
     * None, then the SecurityPolicyUri must be defined. For None we allow an
2045
     * empty SecurityPolicyUri to support all (historical) server behaviors. */
2046
0
    if((asymHeader->securityPolicyUri.length > 0 ||
2047
0
        channel->securityMode != UA_MESSAGESECURITYMODE_NONE) &&
2048
0
       !UA_String_equal(&sp->policyUri, &asymHeader->securityPolicyUri)) {
2049
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
2050
0
                     "The server uses a different SecurityPolicy than "
2051
0
                     "the SecureChannel/Endpoint configured in the client");
2052
0
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
2053
0
    }
2054
2055
    /* In initSecurityPolicy we already verified
2056
     * client->endpoint.serverCertificate and loaded it into the channel context
2057
     * of the SecurityPolicy.
2058
     *
2059
     * If the securityPolicyUri is None (== SecurityMode is None), the server
2060
     * shall ignore the ApplicationInstanceCertificate. Otherwise compare that
2061
     * the certificate in OPN is the same as in the endpoint.
2062
     *
2063
     * Both the clientCertificate of this request and of the endpoint may
2064
     * contain a partial or a complete certificate chain. The compareCertificate
2065
     * function will compare the first certificate of each chain. The end
2066
     * certificate shall be located first in the chain according to the OPC UA
2067
     * specification Part 6 (1.04), chapter 6.2.3.*/
2068
0
    UA_StatusCode res;
2069
0
    if(channel->securityMode != UA_MESSAGESECURITYMODE_NONE) {
2070
0
        void *cc = channel->channelContext;
2071
0
        res = sp->compareCertificate(sp, cc, &asymHeader->senderCertificate);
2072
0
        if(res != UA_STATUSCODE_GOOD) {
2073
0
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
2074
0
                         "The server certificate in the OPN message is "
2075
0
                         "different from the EndpointDescription");
2076
0
            return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
2077
0
        }
2078
0
    }
2079
2080
    /* Verify the certificate the server assumes on our end */
2081
0
    res = sp->compareCertThumbprint(sp, &asymHeader->receiverCertificateThumbprint);
2082
0
    if(res != UA_STATUSCODE_GOOD) {
2083
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
2084
0
                     "The client certificate thumprint in the OPN response "
2085
0
                     "is incorrect");
2086
0
        return res;
2087
0
    }
2088
2089
0
    return UA_STATUSCODE_GOOD;
2090
0
}
2091
2092
/* The local ApplicationUri has to match the certificates of the
2093
 * SecurityPolicies */
2094
static void
2095
0
verifyClientApplicationUri(const UA_Client *client) {
2096
#if UA_LOGLEVEL <= 400
2097
    const UA_ClientConfig *cc = &client->config;
2098
    for(size_t i = 0; i < cc->securityPoliciesSize; i++) {
2099
        UA_SecurityPolicy *sp = &cc->securityPolicies[i];
2100
        if(sp->policyType == UA_SECURITYPOLICYTYPE_NONE &&
2101
           !sp->localCertificate.data)
2102
            continue;
2103
        UA_StatusCode retval =
2104
            UA_CertificateUtils_verifyApplicationUri(&sp->localCertificate,
2105
                                &cc->clientDescription.applicationUri);
2106
        if(retval != UA_STATUSCODE_GOOD) {
2107
            UA_LOG_WARNING(cc->logging, UA_LOGCATEGORY_CLIENT,
2108
                           "The ApplicationUri %S in the client's ApplicationDescription "
2109
                           "does not match the URI specified in the certificate "
2110
                           "for the SecurityPolicy %S",
2111
                           cc->clientDescription.applicationUri, sp->policyUri);
2112
        }
2113
    }
2114
#endif
2115
0
}
2116
2117
static void
2118
delayedNetworkCallback(void *application, void *context);
2119
2120
static void
2121
__Client_networkCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
2122
                         void *application, void **connectionContext,
2123
                         UA_ConnectionState state, const UA_KeyValueMap *params,
2124
0
                         UA_ByteString msg) {
2125
    /* Take the client lock */
2126
0
    UA_Client *client = (UA_Client*)application;
2127
0
    lockClient(client);
2128
2129
0
    UA_LOG_TRACE(client->config.logging, UA_LOGCATEGORY_CLIENT, "Client network callback");
2130
2131
    /* A new connection with no context pointer attached */
2132
0
    if(!*connectionContext) {
2133
        /* Inconsistent SecureChannel state. Has to be fresh for a new
2134
         * connection. */
2135
0
        if(client->channel.state != UA_SECURECHANNELSTATE_CLOSED &&
2136
0
           client->channel.state != UA_SECURECHANNELSTATE_REVERSE_LISTENING) {
2137
0
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
2138
0
                         "Cannot open a connection, the SecureChannel is already used");
2139
0
            setConnectStatus(client, UA_STATUSCODE_BADINTERNALERROR);
2140
0
            notifyClientState(client);
2141
0
            unlockClient(client);
2142
0
            return;
2143
0
        }
2144
2145
        /* Initialize the client connection and attach to the EventLoop connection */
2146
0
        client->channel.connectionManager = cm;
2147
0
        client->channel.connectionId = connectionId;
2148
0
        *connectionContext = &client->channel;
2149
0
    }
2150
2151
    /* The connection is closing in the EventLoop. This is the last callback
2152
     * from that connection. Clean up the SecureChannel in the client. */
2153
0
    if(state == UA_CONNECTIONSTATE_CLOSING) {
2154
0
        UA_LOG_INFO_CHANNEL(client->config.logging, &client->channel,
2155
0
                            "SecureChannel closed");
2156
2157
        /* Set to closing (could be done already in UA_SecureChannel_shutdown).
2158
         * This impacts the handling of cancelled requests below. */
2159
0
        UA_SecureChannelState oldState = client->channel.state;
2160
0
        client->channel.state = UA_SECURECHANNELSTATE_CLOSING;
2161
2162
        /* Set the Session to CREATED if it was ACTIVATED */
2163
0
        if(client->sessionState == UA_SESSIONSTATE_ACTIVATED)
2164
0
            client->sessionState = UA_SESSIONSTATE_CREATED;
2165
2166
        /* Delete outstanding async services - the RequestId is no longer valid. Do
2167
         * this after setting the Session state. Otherwise we send out new Publish
2168
         * Requests immediately. */
2169
0
        __Client_AsyncService_removeAll(client, UA_STATUSCODE_BADSECURECHANNELCLOSED);
2170
2171
        /* Clean up the channel and set the status to CLOSED */
2172
0
        UA_SecureChannel_clear(&client->channel);
2173
2174
        /* The connection closed before it actually opened. Since we are
2175
         * connecting asynchronously, this happens when the TCP connection
2176
         * fails. Try to fall back on the initial EndpointUrl. */
2177
0
        if(oldState == UA_SECURECHANNELSTATE_CONNECTING &&
2178
0
           client->connectStatus == UA_STATUSCODE_GOOD)
2179
0
            setConnectStatus(client, fallbackEndpointUrl(client));
2180
2181
        /* Try to reconnect. Duplicate the code instead of continue_connect to
2182
         * pacify compiler warnings. */
2183
        /* goto continue_connect; */
2184
0
        if(!isFullyConnected(client))
2185
0
            connectActivity(client);
2186
0
        notifyClientState(client);
2187
0
        unlockClient(client);
2188
0
        return;
2189
0
    }
2190
2191
    /* Update the SecureChannel state */
2192
0
    if(UA_LIKELY(state == UA_CONNECTIONSTATE_ESTABLISHED)) {
2193
        /* The connection is now open on the TCP level. Set the SecureChannel
2194
         * state to reflect this. Otherwise later consistency checks for the
2195
         * received messages fail. */
2196
0
        if(client->channel.state < UA_SECURECHANNELSTATE_CONNECTED)
2197
0
            client->channel.state = UA_SECURECHANNELSTATE_CONNECTED;
2198
0
    } else /* state == UA_CONNECTIONSTATE_OPENING */ {
2199
        /* The connection was opened on our end only. Waiting for the TCP handshake
2200
         * to complete. */
2201
0
        client->channel.state = UA_SECURECHANNELSTATE_CONNECTING;
2202
0
    }
2203
2204
0
    UA_EventLoop *el = client->config.eventLoop;
2205
0
    UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);
2206
2207
    /* Received a message. Process the message with the SecureChannel. */
2208
0
    UA_StatusCode res = UA_SecureChannel_loadBuffer(&client->channel, msg);
2209
0
    while(UA_LIKELY(res == UA_STATUSCODE_GOOD)) {
2210
0
        UA_MessageType messageType;
2211
0
        UA_UInt32 requestId = 0;
2212
0
        UA_ByteString payload = UA_BYTESTRING_NULL;
2213
0
        UA_Boolean copied = false;
2214
0
        res = UA_SecureChannel_getCompleteMessage(&client->channel, &messageType, &requestId,
2215
0
                                                  &payload, &copied, nowMonotonic);
2216
0
        if(res != UA_STATUSCODE_GOOD || payload.length == 0)
2217
0
            break;
2218
0
        res = processServiceResponse(client, &client->channel,
2219
0
                                     messageType, requestId, &payload);
2220
0
        if(copied)
2221
0
            UA_ByteString_clear(&payload);
2222
2223
        /* Abort after synchronous processing of a message.
2224
         * Add a delayed callback to process the remaining buffer ASAP. */
2225
0
        if(res == UA_STATUSCODE_GOODCOMPLETESASYNCHRONOUSLY) {
2226
0
            if(client->channel.unprocessed.length > client->channel.unprocessedOffset &&
2227
0
               client->channel.unprocessedDelayed.callback == NULL) {
2228
0
                client->channel.unprocessedDelayed.callback = delayedNetworkCallback;
2229
0
                client->channel.unprocessedDelayed.application = client;
2230
0
                client->channel.unprocessedDelayed.context = &client->channel;
2231
0
                el->addDelayedCallback(el, &client->channel.unprocessedDelayed);
2232
0
            }
2233
0
            res = UA_STATUSCODE_GOOD;
2234
0
            break;
2235
0
        }
2236
0
    }
2237
0
    res |= UA_SecureChannel_persistBuffer(&client->channel);
2238
2239
0
    if(res != UA_STATUSCODE_GOOD) {
2240
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
2241
0
                     "Processing the message returned the error code %s",
2242
0
                     UA_StatusCode_name(res));
2243
2244
        /* If processing the buffer fails before the SecureChannel has opened,
2245
         * then the client cannot recover. Set the connectStatus to reflect
2246
         * this. The application is notified when the socket has closed. */
2247
0
        if(client->channel.state != UA_SECURECHANNELSTATE_OPEN)
2248
0
            setConnectStatus(client, res);
2249
2250
        /* Close the SecureChannel, but don't notify the client right away.
2251
         * Return immediately. notifyClientState will be called in the next
2252
         * callback from the ConnectionManager when the connection closes with a
2253
         * StatusCode.
2254
         *
2255
         * If the connectStatus is still good (the SecureChannel was fully
2256
         * opened before), then a reconnect is attempted. */
2257
0
        closeSecureChannel(client);
2258
0
        unlockClient(client);
2259
0
        return;
2260
0
    }
2261
2262
    /* continue_connect: */
2263
    /* Trigger the next action from our end to fully open up the connection */
2264
0
    if(!isFullyConnected(client))
2265
0
        connectActivity(client);
2266
0
    notifyClientState(client);
2267
0
    unlockClient(client);
2268
0
}
2269
2270
static void
2271
0
delayedNetworkCallback(void *application, void *context) {
2272
0
    UA_Client *client = (UA_Client*)application;
2273
0
    client->channel.unprocessedDelayed.callback = NULL;
2274
0
    if(client->channel.state >= UA_SECURECHANNELSTATE_CONNECTING)
2275
0
        __Client_networkCallback(client->channel.connectionManager,
2276
0
                                 client->channel.connectionId,
2277
0
                                 client, &context,
2278
0
                                 UA_CONNECTIONSTATE_ESTABLISHED,
2279
0
                                 &UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
2280
0
}
2281
2282
/* Initialize a TCP connection. Writes the result to client->connectStatus. */
2283
static void
2284
0
initConnect(UA_Client *client) {
2285
0
    UA_LOCK_ASSERT(&client->clientMutex);
2286
0
    if(client->channel.state != UA_SECURECHANNELSTATE_CLOSED) {
2287
0
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
2288
0
                       "Client connection already initiated");
2289
0
        return;
2290
0
    }
2291
2292
0
    UA_StatusCode res;
2293
2294
    /* An exact endpoint was configured. Use it. */
2295
0
    if(!endpointUnconfigured(&client->config.endpoint)) {
2296
0
        UA_EndpointDescription_clear(&client->endpoint);
2297
0
        res = UA_EndpointDescription_copy(&client->config.endpoint, &client->endpoint);
2298
0
        if(res != UA_STATUSCODE_GOOD) {
2299
0
            setConnectStatus(client, res);
2300
0
            return;
2301
0
        }
2302
0
    }
2303
2304
    /* Start the EventLoop if not already started */
2305
0
    setConnectStatus(client, __UA_Client_startup(client));
2306
0
    if(client->connectStatus != UA_STATUSCODE_GOOD)
2307
0
        return;
2308
2309
    /* Consistency check the client's own ApplicationUri.
2310
     * Problems are only logged. */
2311
0
    verifyClientApplicationUri(client);
2312
2313
    /* Initialize the SecureChannel */
2314
0
    UA_SecureChannel_clear(&client->channel);
2315
0
    client->channel.config = client->config.localConnectionConfig;
2316
0
    client->channel.processOPNHeader = verifyClientSecureChannelHeader;
2317
0
    client->channel.processOPNHeaderApplication = client;
2318
2319
    /* Initialize the SecurityPolicy */
2320
0
    setConnectStatus(client, initSecurityPolicy(client));
2321
0
    if(client->connectStatus != UA_STATUSCODE_GOOD)
2322
0
        return;
2323
2324
    /* Extract hostname and port from the URL */
2325
0
    UA_String hostname = UA_STRING_NULL;
2326
0
    UA_String path = UA_STRING_NULL;
2327
0
    UA_UInt16 port = 4840;
2328
2329
0
    res = UA_parseEndpointUrl(&client->config.endpointUrl, &hostname, &port, &path);
2330
0
    if(res != UA_STATUSCODE_GOOD) {
2331
0
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_NETWORK,
2332
0
                       "Endpoint URL is invalid: %S", client->config.endpointUrl);
2333
0
        setConnectStatus(client, res);
2334
0
        return;
2335
0
    }
2336
2337
    /* Initialize the TCP connection */
2338
0
    UA_String tcpString = UA_STRING("tcp");
2339
0
    for(UA_EventSource *es = client->config.eventLoop->eventSources;
2340
0
        es != NULL; es = es->next) {
2341
        /* Is this a usable connection manager? */
2342
0
        if(es->eventSourceType != UA_EVENTSOURCETYPE_CONNECTIONMANAGER)
2343
0
            continue;
2344
0
        UA_ConnectionManager *cm = (UA_ConnectionManager*)es;
2345
0
        if(!UA_String_equal(&tcpString, &cm->protocol))
2346
0
            continue;
2347
2348
        /* Set up the parameters */
2349
0
        UA_KeyValuePair params[3];
2350
0
        params[0].key = UA_QUALIFIEDNAME(0, "port");
2351
0
        UA_Variant_setScalar(&params[0].value, &port, &UA_TYPES[UA_TYPES_UINT16]);
2352
0
        params[1].key = UA_QUALIFIEDNAME(0, "address");
2353
0
        UA_Variant_setScalar(&params[1].value, &hostname, &UA_TYPES[UA_TYPES_STRING]);
2354
0
        params[2].key = UA_QUALIFIEDNAME(0, "reuse");
2355
0
        UA_Variant_setScalar(&params[2].value, &client->config.tcpReuseAddr,
2356
0
                             &UA_TYPES[UA_TYPES_BOOLEAN]);
2357
2358
0
        UA_KeyValueMap paramMap;
2359
0
        paramMap.map = params;
2360
0
        paramMap.mapSize = 3;
2361
2362
        /* Open the client TCP connection */
2363
0
        res = cm->openConnection(cm, &paramMap, client, NULL, __Client_networkCallback);
2364
0
        if(res == UA_STATUSCODE_GOOD)
2365
0
            break;
2366
0
    }
2367
2368
    /* The channel has not opened */
2369
0
    if(client->channel.state == UA_SECURECHANNELSTATE_CLOSED)
2370
0
        res = UA_STATUSCODE_BADINTERNALERROR;
2371
2372
    /* Opening the TCP connection failed */
2373
0
    if(res != UA_STATUSCODE_GOOD || client->connectStatus != UA_STATUSCODE_GOOD) {
2374
0
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
2375
0
                       "Could not open a TCP connection to %S",
2376
0
                       client->config.endpointUrl);
2377
0
        setConnectStatus(client, UA_STATUSCODE_BADCONNECTIONCLOSED);
2378
0
    }
2379
0
}
2380
2381
void
2382
0
connectSync(UA_Client *client) {
2383
0
    UA_LOCK_ASSERT(&client->clientMutex);
2384
2385
    /* Initialize the connection */
2386
0
    initConnect(client);
2387
0
    notifyClientState(client);
2388
0
    if(client->connectStatus != UA_STATUSCODE_GOOD)
2389
0
        return;
2390
2391
    /* EventLoop is started. Otherwise initConnect would have failed. */
2392
0
    UA_EventLoop *el = client->config.eventLoop;
2393
0
    UA_assert(el);
2394
2395
0
    UA_DateTime now = el->dateTime_nowMonotonic(el);
2396
0
    UA_DateTime maxDate = now + ((UA_DateTime)client->config.timeout * UA_DATETIME_MSEC);
2397
2398
    /* Run the EventLoop until connected, connect fail or timeout. Continue
2399
     * to iterate when the channel is in CLOSING state so that the pending
2400
     * close callback is processed and the channel fully transitions to CLOSED
2401
     * before returning to the caller. */
2402
0
    while((client->connectStatus == UA_STATUSCODE_GOOD && !isFullyConnected(client)) ||
2403
0
          client->channel.state == UA_SECURECHANNELSTATE_CLOSING) {
2404
        /* Timeout -> abort */
2405
0
        now = el->dateTime_nowMonotonic(el);
2406
0
        if(maxDate < now) {
2407
0
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
2408
0
                         "The connection has timed out before it could be fully opened");
2409
0
            setConnectStatus(client, UA_STATUSCODE_BADTIMEOUT);
2410
            /* Continue to run. The loop continues while the channel is
2411
             * CLOSING so the close callback is processed. */
2412
0
        }
2413
2414
        /* Drop into the EventLoop */
2415
0
        UA_StatusCode res = el->run(el, (UA_UInt32)((maxDate - now) / UA_DATETIME_MSEC));
2416
0
        if(res != UA_STATUSCODE_GOOD)
2417
0
            setConnectStatus(client, res);
2418
0
    }
2419
0
}
2420
2421
UA_StatusCode
2422
0
connectInternal(UA_Client *client, UA_Boolean async) {
2423
0
    UA_LOCK_ASSERT(&client->clientMutex);
2424
2425
    /* Reset the connectStatus. This should be the only place where we can
2426
     * recover from a bad connectStatus. */
2427
0
    client->connectStatus = UA_STATUSCODE_GOOD;
2428
2429
0
    if(async)
2430
0
        initConnect(client);
2431
0
    else
2432
0
        connectSync(client);
2433
0
    notifyClientState(client);
2434
0
    return client->connectStatus;
2435
0
}
2436
2437
UA_StatusCode
2438
0
connectSecureChannel(UA_Client *client, const char *endpointUrl) {
2439
0
    UA_LOCK_ASSERT(&client->clientMutex);
2440
2441
0
    UA_ClientConfig *cc = UA_Client_getConfig(client);
2442
0
    cc->noSession = true;
2443
0
    UA_String_clear(&cc->endpointUrl);
2444
0
    cc->endpointUrl = UA_STRING_ALLOC(endpointUrl);
2445
0
    return connectInternal(client, false);
2446
0
}
2447
2448
UA_StatusCode
2449
0
__UA_Client_connect(UA_Client *client, UA_Boolean async, const char *endpointUrl) {
2450
0
    lockClient(client);
2451
2452
0
    UA_ClientConfig *cc = UA_Client_getConfig(client);
2453
0
    if(endpointUrl) {
2454
0
        UA_String_clear(&cc->endpointUrl);
2455
0
        cc->endpointUrl = UA_STRING_ALLOC(endpointUrl);
2456
0
    }
2457
2458
0
    connectInternal(client, async);
2459
2460
0
    unlockClient(client);
2461
0
    return client->connectStatus;
2462
0
}
2463
2464
static UA_StatusCode
2465
0
activateSessionSync(UA_Client *client) {
2466
0
    UA_LOCK_ASSERT(&client->clientMutex);
2467
2468
    /* EventLoop is started. Otherwise activateSessionAsync would have failed. */
2469
0
    UA_EventLoop *el = client->config.eventLoop;
2470
0
    UA_assert(el);
2471
2472
0
    UA_DateTime now = el->dateTime_nowMonotonic(el);
2473
0
    UA_DateTime maxDate = now + ((UA_DateTime)client->config.timeout * UA_DATETIME_MSEC);
2474
2475
    /* Try to activate */
2476
0
    UA_StatusCode res = activateSessionAsync(client);
2477
0
    if(res != UA_STATUSCODE_GOOD)
2478
0
        return res;
2479
2480
    /* Continue iterating while the session is being activated or the
2481
     * channel is draining (CLOSING) after a timeout. */
2482
0
    while((client->sessionState != UA_SESSIONSTATE_ACTIVATED &&
2483
0
          client->connectStatus == UA_STATUSCODE_GOOD) ||
2484
0
          client->channel.state == UA_SECURECHANNELSTATE_CLOSING) {
2485
        /* Timeout -> abort */
2486
0
        now = el->dateTime_nowMonotonic(el);
2487
0
        if(maxDate < now) {
2488
0
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
2489
0
                         "The connection has timed out before it could be fully opened");
2490
0
            setConnectStatus(client, UA_STATUSCODE_BADTIMEOUT);
2491
            /* Continue to run. The loop continues while the channel is
2492
             * CLOSING so the close callback is processed. */
2493
0
        }
2494
2495
        /* Drop into the EventLoop */
2496
0
        res = el->run(el, (UA_UInt32)((maxDate - now) / UA_DATETIME_MSEC));
2497
0
        if(res != UA_STATUSCODE_GOOD)
2498
0
            setConnectStatus(client, res);
2499
0
    }
2500
2501
0
    return client->connectStatus;
2502
0
}
2503
2504
UA_StatusCode
2505
0
UA_Client_activateCurrentSession(UA_Client *client) {
2506
0
    lockClient(client);
2507
0
    UA_StatusCode res = activateSessionSync(client);
2508
0
    notifyClientState(client);
2509
0
    unlockClient(client);
2510
0
    return res != UA_STATUSCODE_GOOD ? res : client->connectStatus;
2511
0
}
2512
2513
UA_StatusCode
2514
0
UA_Client_activateCurrentSessionAsync(UA_Client *client) {
2515
0
    lockClient(client);
2516
0
    UA_StatusCode res = activateSessionAsync(client);
2517
0
    notifyClientState(client);
2518
0
    unlockClient(client);
2519
0
    return res != UA_STATUSCODE_GOOD ? res : client->connectStatus;
2520
0
}
2521
2522
UA_StatusCode
2523
UA_Client_getSessionAuthenticationToken(UA_Client *client,
2524
                                        UA_NodeId *authenticationToken,
2525
0
                                        UA_ByteString *serverNonce) {
2526
0
    lockClient(client);
2527
0
    if(client->sessionState != UA_SESSIONSTATE_CREATED &&
2528
0
       client->sessionState != UA_SESSIONSTATE_ACTIVATED) {
2529
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
2530
0
                     "There is no current session");
2531
0
        unlockClient(client);
2532
0
        return UA_STATUSCODE_BADSESSIONCLOSED;
2533
0
    }
2534
2535
0
    UA_StatusCode res =
2536
0
        UA_NodeId_copy(&client->authenticationToken, authenticationToken);
2537
0
    res |= UA_ByteString_copy(&client->serverSessionNonce, serverNonce);
2538
0
    unlockClient(client);
2539
0
    return res;
2540
0
}
2541
2542
static UA_StatusCode
2543
switchSession(UA_Client *client,
2544
              const UA_NodeId authenticationToken,
2545
0
              const UA_ByteString serverNonce) {
2546
    /* Check that there is no pending session in the client */
2547
0
    if(client->sessionState != UA_SESSIONSTATE_CLOSED) {
2548
0
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
2549
0
                     "Cannot activate a session with a different AuthenticationToken "
2550
0
                     "when the client already has a Session.");
2551
0
        return UA_STATUSCODE_BADINTERNALERROR;
2552
0
    }
2553
2554
    /* Replace token and nonce */
2555
0
    UA_NodeId_clear(&client->authenticationToken);
2556
0
    UA_ByteString_clear(&client->serverSessionNonce);
2557
0
    UA_StatusCode res = UA_NodeId_copy(&authenticationToken,
2558
0
                                       &client->authenticationToken);
2559
0
    res |= UA_ByteString_copy(&serverNonce, &client->serverSessionNonce);
2560
0
    if(res != UA_STATUSCODE_GOOD)
2561
0
        return res;
2562
2563
    /* Notify that we have now a created session */
2564
0
    client->sessionState = UA_SESSIONSTATE_CREATED;
2565
0
    notifyClientState(client);
2566
2567
0
    return UA_STATUSCODE_GOOD;
2568
0
}
2569
2570
UA_StatusCode
2571
UA_Client_activateSession(UA_Client *client,
2572
                          const UA_NodeId authenticationToken,
2573
0
                          const UA_ByteString serverNonce) {
2574
0
    lockClient(client);
2575
0
    UA_StatusCode res = switchSession(client, authenticationToken, serverNonce);
2576
0
    if(res != UA_STATUSCODE_GOOD) {
2577
0
        unlockClient(client);
2578
0
        return res;
2579
0
    }
2580
0
    res = activateSessionSync(client);
2581
0
    notifyClientState(client);
2582
0
    unlockClient(client);
2583
0
    return res != UA_STATUSCODE_GOOD ? res : client->connectStatus;
2584
0
}
2585
2586
UA_StatusCode
2587
UA_Client_activateSessionAsync(UA_Client *client,
2588
                               const UA_NodeId authenticationToken,
2589
0
                               const UA_ByteString serverNonce) {
2590
0
    lockClient(client);
2591
0
    UA_StatusCode res = switchSession(client, authenticationToken, serverNonce);
2592
0
    if(res != UA_STATUSCODE_GOOD) {
2593
0
        unlockClient(client);
2594
0
        return res;
2595
0
    }
2596
0
    res = activateSessionAsync(client);
2597
0
    notifyClientState(client);
2598
0
    unlockClient(client);
2599
0
    return res != UA_STATUSCODE_GOOD ? res : client->connectStatus;
2600
0
}
2601
2602
static void
2603
0
disconnectListenSockets(UA_Client *client) {
2604
0
    UA_ConnectionManager *cm = client->reverseConnectionCM;
2605
0
    for(size_t i = 0; i < 16; i++) {
2606
0
        if(client->reverseConnectionIds[i] != 0)
2607
0
            cm->closeConnection(cm, client->reverseConnectionIds[i]);
2608
0
    }
2609
0
}
2610
2611
/* ConnectionContext meaning:
2612
 * - NULL: New listen connection
2613
 * - &client->channel: Established active socket to a server
2614
 * - &client->reverseConnectionIds[*] == connectionId: Established listen socket
2615
 * - &client->reverseConnectionIds[*] != connectionId: New active socket */
2616
static void
2617
__Client_reverseConnectCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
2618
                                void *application, void **connectionContext,
2619
                                UA_ConnectionState state, const UA_KeyValueMap *params,
2620
0
                                UA_ByteString msg) {
2621
0
    UA_Client *client = (UA_Client*)application;
2622
0
    lockClient(client);
2623
2624
0
    if(!*connectionContext) {
2625
        /* Store the new listen connection */
2626
0
        size_t i = 0;
2627
0
        for(; i < 16; i++) {
2628
0
            if(client->reverseConnectionIds[i] == 0) {
2629
0
                client->reverseConnectionIds[i] = connectionId;
2630
0
                client->reverseConnectionCM = cm;
2631
0
                *connectionContext = &client->reverseConnectionIds[i];
2632
0
                if(client->channel.state == UA_SECURECHANNELSTATE_CLOSED)
2633
0
                    client->channel.state = UA_SECURECHANNELSTATE_REVERSE_LISTENING;
2634
0
                break;
2635
0
            }
2636
0
        }
2637
        /* All slots are full, close */
2638
0
        if(i == 16) {
2639
0
            cm->closeConnection(cm, connectionId);
2640
0
            unlockClient(client);
2641
0
            return;
2642
0
        }
2643
0
    } else if(*connectionContext == &client->channel ||
2644
0
              *(uintptr_t*)*connectionContext != connectionId) {
2645
        /* Active socket */
2646
2647
        /* New active socket */
2648
0
        if(*connectionContext != &client->channel) {
2649
            /* The client already has an active connection */
2650
0
            if(client->channel.connectionId) {
2651
0
                cm->closeConnection(cm, connectionId);
2652
0
                unlockClient(client);
2653
0
                return;
2654
0
            }
2655
2656
            /* Set the connection the SecureChannel */
2657
0
            client->channel.connectionId = connectionId;
2658
0
            client->channel.connectionManager = cm;
2659
0
            *connectionContext = &client->channel;
2660
2661
            /* Don't keep the listen sockets when an active connection is open */
2662
0
            disconnectListenSockets(client);
2663
2664
            /* Set the channel state. The notification callback is called within
2665
             * __Client_reverseConnectCallback. */
2666
0
            if(client->channel.state == UA_SECURECHANNELSTATE_REVERSE_LISTENING)
2667
0
                client->channel.state = UA_SECURECHANNELSTATE_REVERSE_CONNECTED;
2668
0
        }
2669
2670
        /* Handle the active connection in the normal network callback */
2671
0
        unlockClient(client);
2672
0
        __Client_networkCallback(cm, connectionId, application,
2673
0
                                 connectionContext, state, params, msg);
2674
0
        return;
2675
0
    }
2676
2677
    /* Close the listen socket. Was this the last one? */
2678
0
    if(state == UA_CONNECTIONSTATE_CLOSING) {
2679
0
        UA_Byte count = 0;
2680
0
        for(size_t i = 0; i < 16; i++) {
2681
0
            if(client->reverseConnectionIds[i] == connectionId)
2682
0
                client->reverseConnectionIds[i] = 0;
2683
0
            if(client->reverseConnectionIds[i] != 0)
2684
0
                count++;
2685
0
        }
2686
        /* The last connection was closed */
2687
0
        if(count == 0 && client->channel.connectionId == 0)
2688
0
            client->channel.state = UA_SECURECHANNELSTATE_CLOSED;
2689
0
    }
2690
2691
0
    notifyClientState(client);
2692
0
    unlockClient(client);
2693
0
}
2694
2695
UA_StatusCode
2696
UA_Client_startListeningForReverseConnect(UA_Client *client,
2697
                                          const UA_String *listenHostnames,
2698
                                          size_t listenHostnamesLength,
2699
0
                                          UA_UInt16 port) {
2700
0
    lockClient(client);
2701
2702
0
    if(client->channel.state != UA_SECURECHANNELSTATE_CLOSED) {
2703
0
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
2704
0
                       "Unable to listen for reverse connect while the client "
2705
0
                       "is connected or already listening");
2706
0
        unlockClient(client);
2707
0
        return UA_STATUSCODE_BADINVALIDSTATE;
2708
0
    }
2709
2710
0
    const UA_String tcpString = UA_STRING_STATIC("tcp");
2711
0
    UA_StatusCode res = UA_STATUSCODE_BADINTERNALERROR;
2712
2713
0
    client->connectStatus = UA_STATUSCODE_GOOD;
2714
0
    client->channel.renewState = UA_SECURECHANNELRENEWSTATE_NORMAL;
2715
2716
0
    UA_SecureChannel_init(&client->channel);
2717
0
    client->channel.config = client->config.localConnectionConfig;
2718
0
    client->channel.processOPNHeader = verifyClientSecureChannelHeader;
2719
0
    client->channel.processOPNHeaderApplication = client;
2720
0
    client->channel.connectionId = 0;
2721
2722
0
    setConnectStatus(client, initSecurityPolicy(client));
2723
0
    if(client->connectStatus != UA_STATUSCODE_GOOD)
2724
0
        return client->connectStatus;
2725
2726
0
    UA_EventLoop *el = client->config.eventLoop;
2727
0
    if(!el) {
2728
0
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
2729
0
                       "No EventLoop configured");
2730
0
        unlockClient(client);
2731
0
        return UA_STATUSCODE_BADINTERNALERROR;
2732
0
    }
2733
2734
0
    if(el->state != UA_EVENTLOOPSTATE_STARTED) {
2735
0
        res = el->start(el);
2736
0
        UA_CHECK_STATUS(res, unlockClient(client); return res);
2737
0
    }
2738
2739
0
    UA_ConnectionManager *cm = NULL;
2740
0
    for(UA_EventSource *es = el->eventSources; es != NULL; es = es->next) {
2741
0
        if(es->eventSourceType != UA_EVENTSOURCETYPE_CONNECTIONMANAGER)
2742
0
            continue;
2743
0
        cm = (UA_ConnectionManager*)es;
2744
0
        if(UA_String_equal(&tcpString, &cm->protocol))
2745
0
            break;
2746
0
        cm = NULL;
2747
0
    }
2748
2749
0
    if(!cm) {
2750
0
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
2751
0
                       "Could not find a TCP connection manager, unable to "
2752
0
                       "listen for reverse connect");
2753
0
        unlockClient(client);
2754
0
        return UA_STATUSCODE_BADINTERNALERROR;
2755
0
    }
2756
2757
0
    client->channel.connectionManager = cm;
2758
2759
0
    UA_KeyValuePair params[4];
2760
0
    bool booleanTrue = true;
2761
0
    params[0].key = UA_QUALIFIEDNAME(0, "port");
2762
0
    UA_Variant_setScalar(&params[0].value, &port,
2763
0
                         &UA_TYPES[UA_TYPES_UINT16]);
2764
0
    params[1].key = UA_QUALIFIEDNAME(0, "address");
2765
0
    UA_Variant_setArray(&params[1].value, (void *)(uintptr_t)listenHostnames,
2766
0
            listenHostnamesLength, &UA_TYPES[UA_TYPES_STRING]);
2767
0
    params[2].key = UA_QUALIFIEDNAME(0, "listen");
2768
0
    UA_Variant_setScalar(&params[2].value, &booleanTrue,
2769
0
                         &UA_TYPES[UA_TYPES_BOOLEAN]);
2770
0
    params[3].key = UA_QUALIFIEDNAME(0, "reuse");
2771
0
    UA_Variant_setScalar(&params[3].value, &client->config.tcpReuseAddr,
2772
0
                         &UA_TYPES[UA_TYPES_BOOLEAN]);
2773
2774
0
    UA_KeyValueMap paramMap;
2775
0
    paramMap.map = params;
2776
0
    paramMap.mapSize = 4;
2777
2778
0
    res = cm->openConnection(cm, &paramMap, client, NULL,
2779
0
                             __Client_reverseConnectCallback);
2780
2781
    /* Opening the TCP connection failed */
2782
0
    if(res != UA_STATUSCODE_GOOD) {
2783
0
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
2784
0
                       "Failed to open a listening TCP socket for "
2785
0
                       "reverse connect");
2786
0
        res = UA_STATUSCODE_BADCONNECTIONCLOSED;
2787
0
    }
2788
2789
0
    unlockClient(client);
2790
0
    return res;
2791
0
}
2792
2793
/************************/
2794
/* Close the Connection */
2795
/************************/
2796
2797
void
2798
40
closeSecureChannel(UA_Client *client) {
2799
    /* If we close SecureChannel when the Session is still active, set to
2800
     * created. Otherwise the Session would remain active until the connection
2801
     * callback is called for the closing connection. */
2802
40
    if(client->sessionState == UA_SESSIONSTATE_ACTIVATED)
2803
0
        client->sessionState = UA_SESSIONSTATE_CREATED;
2804
2805
    /* Prevent recursion */
2806
40
    if(client->channel.state == UA_SECURECHANNELSTATE_CLOSING ||
2807
0
       client->channel.state == UA_SECURECHANNELSTATE_CLOSED)
2808
40
        return;
2809
2810
0
    UA_LOG_DEBUG_CHANNEL(client->config.logging, &client->channel,
2811
0
                         "Closing the channel");
2812
2813
0
    disconnectListenSockets(client);
2814
2815
    /* Send CLO if the SecureChannel is open */
2816
0
    if(client->channel.state == UA_SECURECHANNELSTATE_OPEN) {
2817
0
        UA_LOG_DEBUG_CHANNEL(client->config.logging, &client->channel,
2818
0
                             "Sending the CLO message");
2819
2820
0
        UA_EventLoop *el = client->config.eventLoop;
2821
2822
        /* Manually set up the header (otherwise done in sendRequest) */
2823
0
        UA_CloseSecureChannelRequest request;
2824
0
        UA_CloseSecureChannelRequest_init(&request);
2825
0
        request.requestHeader.requestHandle = ++client->requestHandle;
2826
0
        request.requestHeader.timestamp = el->dateTime_now(el);
2827
0
        request.requestHeader.timeoutHint = client->config.timeout;
2828
0
        request.requestHeader.authenticationToken = client->authenticationToken;
2829
0
        UA_SecureChannel_sendCLO(&client->channel, ++client->requestId, &request);
2830
0
    }
2831
2832
    /* The connection is eventually closed in the next callback from the
2833
     * ConnectionManager with the appropriate status code. Don't set the
2834
     * connection closed right away! */
2835
0
    UA_SecureChannel_shutdown(&client->channel, UA_SHUTDOWNREASON_CLOSE);
2836
0
}
2837
2838
static void
2839
40
sendCloseSession(UA_Client *client) {
2840
40
    UA_CloseSessionRequest request;
2841
40
    UA_CloseSessionRequest_init(&request);
2842
40
    request.deleteSubscriptions = true;
2843
40
    UA_CloseSessionResponse response;
2844
40
    __Client_Service(client, &request, &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST],
2845
40
                        &response, &UA_TYPES[UA_TYPES_CLOSESESSIONRESPONSE]);
2846
40
    UA_CloseSessionRequest_clear(&request);
2847
40
    UA_CloseSessionResponse_clear(&response);
2848
2849
    /* Set after sending the message to prevent immediate reoping during the
2850
     * service call */
2851
40
    client->sessionState = UA_SESSIONSTATE_CLOSING;
2852
40
}
2853
2854
void
2855
80
cleanupSession(UA_Client *client) {
2856
80
    UA_NodeId_clear(&client->sessionId);
2857
80
    UA_NodeId_clear(&client->authenticationToken);
2858
80
    client->requestHandle = 0;
2859
2860
80
#ifdef UA_ENABLE_SUBSCRIPTIONS
2861
    /* We need to clean up the subscriptions */
2862
80
    __Client_Subscriptions_clear(client);
2863
80
#endif
2864
2865
    /* Delete outstanding async services */
2866
80
    __Client_AsyncService_removeAll(client, UA_STATUSCODE_BADSESSIONCLOSED);
2867
2868
80
#ifdef UA_ENABLE_SUBSCRIPTIONS
2869
80
    client->currentlyOutStandingPublishRequests = 0;
2870
80
#endif
2871
2872
80
    client->sessionState = UA_SESSIONSTATE_CLOSED;
2873
2874
    /* Clean the latest server's ephemeral public key */
2875
80
    UA_ByteString_clear(&client->serverEphemeralPubKey);
2876
80
    if(client->utpSp && client->utpSpContext)
2877
0
        client->utpSp->deleteChannelContext(client->utpSp, client->utpSpContext);
2878
    /* The None policy has no context, but its policy reference must still be
2879
     * reset so a new Session can select a different authentication policy. */
2880
80
    client->utpSp = NULL;
2881
80
    client->utpSpContext = NULL;
2882
80
}
2883
2884
static void
2885
80
disconnectSecureChannel(UA_Client *client, UA_Boolean sync) {
2886
    /* Clean the DiscoveryUrl and endpoint description when the connection is
2887
     * explicitly closed */
2888
80
    UA_String_clear(&client->discoveryUrl);
2889
80
    UA_EndpointDescription_clear(&client->endpoint);
2890
2891
    /* Close the SecureChannel */
2892
80
    closeSecureChannel(client);
2893
2894
    /* Manually set the status to closed to prevent an automatic reconnection.
2895
     * Notify the client at the end. */
2896
80
    if(client->connectStatus == UA_STATUSCODE_GOOD)
2897
40
        client->connectStatus = UA_STATUSCODE_BADCONNECTIONCLOSED;
2898
2899
    /* In the synchronous case, loop until the client has actually closed. */
2900
80
    UA_EventLoop *el = client->config.eventLoop;
2901
80
    if(sync && el &&
2902
80
       el->state != UA_EVENTLOOPSTATE_FRESH &&
2903
0
       el->state != UA_EVENTLOOPSTATE_STOPPED) {
2904
0
        while(client->channel.state != UA_SECURECHANNELSTATE_CLOSED) {
2905
0
            UA_StatusCode runStatus = el->run(el, 100);
2906
0
            if(runStatus != UA_STATUSCODE_GOOD) {
2907
0
                UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
2908
0
                             "EventLoop run returned %s during synchronous disconnect, "
2909
0
                             "stopping wait loop", UA_StatusCode_name(runStatus));
2910
0
                break;
2911
0
            }
2912
0
        }
2913
0
    }
2914
2915
80
    notifyClientState(client);
2916
80
}
2917
2918
UA_StatusCode
2919
0
UA_Client_disconnectSecureChannel(UA_Client *client) {
2920
0
    lockClient(client);
2921
0
    disconnectSecureChannel(client, true);
2922
0
    unlockClient(client);
2923
0
    return UA_STATUSCODE_GOOD;
2924
0
}
2925
2926
UA_StatusCode
2927
0
UA_Client_disconnectSecureChannelAsync(UA_Client *client) {
2928
0
    lockClient(client);
2929
0
    disconnectSecureChannel(client, false);
2930
0
    unlockClient(client);
2931
0
    return UA_STATUSCODE_GOOD;
2932
0
}
2933
2934
UA_StatusCode
2935
80
UA_Client_disconnect(UA_Client *client) {
2936
80
    lockClient(client);
2937
80
    if(client->sessionState == UA_SESSIONSTATE_ACTIVATED)
2938
40
        sendCloseSession(client);
2939
80
    cleanupSession(client);
2940
80
    disconnectSecureChannel(client, true);
2941
80
    unlockClient(client);
2942
80
    return UA_STATUSCODE_GOOD;
2943
80
}
2944
2945
static void
2946
closeSessionCallback(UA_Client *client, void *userdata,
2947
0
                     UA_UInt32 requestId, void *response) {
2948
0
    lockClient(client);
2949
0
    cleanupSession(client);
2950
0
    disconnectSecureChannel(client, false);
2951
0
    notifyClientState(client);
2952
0
    unlockClient(client);
2953
0
}
2954
2955
UA_StatusCode
2956
0
UA_Client_disconnectAsync(UA_Client *client) {
2957
0
    lockClient(client);
2958
2959
0
    if(client->sessionState == UA_SESSIONSTATE_CLOSED ||
2960
0
       client->sessionState == UA_SESSIONSTATE_CLOSING) {
2961
0
        disconnectSecureChannel(client, false);
2962
0
        notifyClientState(client);
2963
0
        unlockClient(client);
2964
0
        return UA_STATUSCODE_GOOD;
2965
0
    }
2966
2967
    /* Set before sending the message to prevent recursion */
2968
0
    client->sessionState = UA_SESSIONSTATE_CLOSING;
2969
2970
0
    UA_CloseSessionRequest request;
2971
0
    UA_CloseSessionRequest_init(&request);
2972
0
    request.deleteSubscriptions = true;
2973
0
    UA_StatusCode res =
2974
0
        __Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST],
2975
0
                              (UA_ClientAsyncServiceCallback)closeSessionCallback,
2976
0
                              &UA_TYPES[UA_TYPES_CLOSESESSIONRESPONSE], NULL, NULL);
2977
0
    if(res != UA_STATUSCODE_GOOD) {
2978
        /* Sending the close request failed. Continue to close the connection
2979
         * anyway. */
2980
0
        cleanupSession(client);
2981
0
        disconnectSecureChannel(client, false);
2982
0
    }
2983
2984
0
    notifyClientState(client);
2985
0
    unlockClient(client);
2986
0
    return res;
2987
0
}