/src/open62541_15/src/ua_securechannel_crypto.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 2014-2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer) |
6 | | * Copyright 2014, 2016-2017 (c) Florian Palm |
7 | | * Copyright 2015-2016 (c) Sten Grüner |
8 | | * Copyright 2015 (c) Oleksiy Vasylyev |
9 | | * Copyright 2016 (c) TorbenD |
10 | | * Copyright 2017 (c) Stefan Profanter, fortiss GmbH |
11 | | * Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB |
12 | | * Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer) |
13 | | * Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner) |
14 | | */ |
15 | | |
16 | | #include "open62541/transport_generated.h" |
17 | | #include "ua_securechannel.h" |
18 | | #include "ua_types_encoding_binary.h" |
19 | | |
20 | | UA_StatusCode |
21 | | UA_CertificateUtils_checkExtendedKeyUsage(const UA_ByteString *certificate, |
22 | | UA_CertificateEku requestedUsage, |
23 | 0 | UA_Boolean ekuRequired) { |
24 | 0 | UA_CertificateEku eku = UA_CERTIFICATEEKU_NONE; |
25 | 0 | UA_StatusCode res = |
26 | 0 | UA_CertificateUtils_getExtendedKeyUsage(certificate, &eku); |
27 | 0 | if(res != UA_STATUSCODE_GOOD) |
28 | 0 | return res; |
29 | | |
30 | 0 | if(eku == UA_CERTIFICATEEKU_NONE) |
31 | 0 | return ekuRequired ? UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED : |
32 | 0 | UA_STATUSCODE_GOOD; |
33 | | |
34 | 0 | if((eku & (requestedUsage | UA_CERTIFICATEEKU_ANY)) != 0) |
35 | 0 | return UA_STATUSCODE_GOOD; |
36 | 0 | return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED; |
37 | 0 | } |
38 | | |
39 | | UA_StatusCode |
40 | 112 | UA_SecureChannel_generateLocalNonce(UA_SecureChannel *channel) { |
41 | 112 | const UA_SecurityPolicy *sp = channel->securityPolicy; |
42 | 112 | UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR); |
43 | 112 | UA_LOG_DEBUG_CHANNEL(sp->logger, channel, "Generating new local nonce"); |
44 | | |
45 | | /* Is the length of the previous nonce correct? The SecureChannel nonce has |
46 | | * exactly the SecureChannelNonceLength of the SecurityPolicy (Part 7). |
47 | | * E.g. 16 byte for Basic128Rsa15; other stacks reject a longer nonce |
48 | | * with Bad_NonceInvalid. */ |
49 | 112 | size_t nonceLength = sp->nonceLength; |
50 | 112 | if(nonceLength == 0) |
51 | 112 | return UA_STATUSCODE_GOOD; |
52 | | |
53 | 0 | if(channel->localNonce.length != nonceLength) { |
54 | 0 | UA_ByteString_clear(&channel->localNonce); |
55 | 0 | UA_StatusCode res = UA_ByteString_allocBuffer(&channel->localNonce, nonceLength); |
56 | 0 | UA_CHECK_STATUS(res, return res); |
57 | 0 | } |
58 | | |
59 | | /* Generate the nonce */ |
60 | 0 | channel->localNonce.data[0] = 'e'; |
61 | 0 | channel->localNonce.data[1] = 'p'; |
62 | 0 | channel->localNonce.data[2] = 'h'; |
63 | 0 | return sp->generateNonce(sp, channel->channelContext, &channel->localNonce); |
64 | 0 | } |
65 | | |
66 | | /* OPC UA Part 6 v1.05.07 §6.8.1 step 2 "Extract" — IKM chaining (enhanced |
67 | | * policies only). The IKM is XORed with the new shared secret on each renewal; |
68 | | * the accumulator is the curve's coordinate size (half the nonceLength, e.g. 32 |
69 | | * bytes for P-256). It is carried through sp->generateKey without changing that |
70 | | * signature by prepending it to the `secret` ByteString: the backend's |
71 | | * DeriveKeys helper detects the prepend (key1 longer than the ephemeral public |
72 | | * key), XORs, and writes the chained IKM back into the slot. */ |
73 | | #define IKM_PREPEND_LENGTH(channel) \ |
74 | 0 | ((channel)->enhancedSecurity ? ((channel)->securityPolicy->nonceLength / 2) : 0) |
75 | | |
76 | | /* Allocate and fill the prepend buffer [currentIKM | nonce] when |
77 | | * chaining is active; otherwise point *outInput at the original |
78 | | * nonce. The caller frees *outCombined with UA_ByteString_clear. */ |
79 | | static UA_StatusCode |
80 | | prepareKeyInput(UA_SecureChannel *channel, const UA_ByteString *nonce, |
81 | 0 | UA_ByteString *outInput, UA_ByteString *outCombined) { |
82 | 0 | size_t ikmLen = IKM_PREPEND_LENGTH(channel); |
83 | 0 | if(ikmLen == 0) { |
84 | 0 | *outInput = *nonce; |
85 | 0 | *outCombined = UA_BYTESTRING_NULL; |
86 | 0 | return UA_STATUSCODE_GOOD; |
87 | 0 | } |
88 | 0 | UA_StatusCode res = |
89 | 0 | UA_ByteString_allocBuffer(outCombined, ikmLen + nonce->length); |
90 | 0 | if(res != UA_STATUSCODE_GOOD) |
91 | 0 | return res; |
92 | 0 | if(channel->currentIKM.length == ikmLen) |
93 | 0 | memcpy(outCombined->data, channel->currentIKM.data, ikmLen); |
94 | 0 | else |
95 | 0 | memset(outCombined->data, 0, ikmLen); |
96 | 0 | memcpy(outCombined->data + ikmLen, nonce->data, nonce->length); |
97 | 0 | *outInput = *outCombined; |
98 | 0 | return UA_STATUSCODE_GOOD; |
99 | 0 | } |
100 | | |
101 | | /* Pull the (possibly updated) IKM from the prepend slot and store |
102 | | * it as channel->currentIKM. Called only by the local-keys pass; |
103 | | * the remote-keys pass leaves the accumulator untouched. */ |
104 | | static UA_StatusCode |
105 | 0 | captureIKMSlot(UA_SecureChannel *channel, const UA_ByteString *combined) { |
106 | 0 | size_t ikmLen = IKM_PREPEND_LENGTH(channel); |
107 | 0 | if(ikmLen == 0) |
108 | 0 | return UA_STATUSCODE_GOOD; |
109 | 0 | UA_ByteString_clear(&channel->currentIKM); |
110 | 0 | UA_ByteString ikmSlot = {ikmLen, combined->data}; |
111 | 0 | return UA_ByteString_copy(&ikmSlot, &channel->currentIKM); |
112 | 0 | } |
113 | | |
114 | | /* OPC UA Part 6, 6.8.1 Step 1: "When not using AuthenticatedEncryption with |
115 | | * Sign only, the EncryptionKeyLength and InitializationVectorLength are set to |
116 | | * 0 in the calculation of L." L is part of the HKDF salt and the length of the |
117 | | * derived key material, so only the signing key is derived for the ECC |
118 | | * policies without AEAD in the SecurityMode Sign. The encrypting key and IV |
119 | | * are not used in this mode and stay zeroed. */ |
120 | | static size_t |
121 | | derivedKeyMaterialLength(const UA_SecureChannel *channel, size_t signKL, |
122 | 0 | size_t totalLength) { |
123 | 0 | if(channel->securityPolicy->policyType == UA_SECURITYPOLICYTYPE_ECC && |
124 | 0 | channel->securityMode == UA_MESSAGESECURITYMODE_SIGN) |
125 | 0 | return signKL; |
126 | 0 | return totalLength; |
127 | 0 | } |
128 | | |
129 | | UA_StatusCode |
130 | 0 | UA_SecureChannel_generateLocalKeys(UA_SecureChannel *channel) { |
131 | 0 | const UA_SecurityPolicy *sp = channel->securityPolicy; |
132 | 0 | UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR); |
133 | 0 | UA_LOG_DEBUG_CHANNEL(sp->logger, channel, "Generating new local keys"); |
134 | |
|
135 | 0 | void *cc = channel->channelContext; |
136 | 0 | const UA_SecurityPolicyEncryptionAlgorithm *ea = &sp->symEncryptionAlgorithm; |
137 | | |
138 | | /* Generate symmetric key buffer of the required length. The block size is |
139 | | * identical for local/remote. For AEAD ciphers the IV length differs from |
140 | | * the block size, so use getLocalIvLength when available. */ |
141 | 0 | UA_ByteString buf; |
142 | 0 | size_t encrKL = ea->getLocalKeyLength(sp, cc); |
143 | 0 | size_t encrBS = ea->getRemoteBlockSize(sp, cc); |
144 | 0 | size_t ivLen = ea->getLocalIvLength ? ea->getLocalIvLength(sp, cc) : encrBS; |
145 | 0 | size_t signKL = sp->symSignatureAlgorithm.getLocalKeyLength(sp, cc); |
146 | 0 | if(ivLen + signKL + encrKL == 0) |
147 | 0 | return UA_STATUSCODE_GOOD; /* No keys to generate */ |
148 | | |
149 | 0 | UA_StatusCode res = UA_ByteString_allocBuffer(&buf, ivLen + signKL + encrKL); |
150 | 0 | UA_CHECK_STATUS(res, return res); |
151 | 0 | UA_ByteString localSigningKey = {signKL, buf.data}; |
152 | 0 | UA_ByteString localEncryptingKey = {encrKL, &buf.data[signKL]}; |
153 | 0 | UA_ByteString localIv = {ivLen, &buf.data[signKL + encrKL]}; |
154 | 0 | memset(buf.data, 0, buf.length); |
155 | 0 | UA_ByteString derived = { |
156 | 0 | derivedKeyMaterialLength(channel, signKL, buf.length), buf.data}; |
157 | | |
158 | | /* Build the IKM-prefixed `secret` input (the helper detects |
159 | | * the prepend via the length mismatch against the local |
160 | | * ephemeral public key). The `seed` arg is passed unchanged — |
161 | | * the helper uses it as the alternate ephemeral public key |
162 | | * candidate and as part of the salt, so the prepend must not |
163 | | * appear there. */ |
164 | 0 | UA_ByteString secretInput, seedInput = channel->localNonce; |
165 | 0 | UA_ByteString secretCombined = UA_BYTESTRING_NULL; |
166 | 0 | res = prepareKeyInput(channel, &channel->remoteNonce, |
167 | 0 | &secretInput, &secretCombined); |
168 | 0 | UA_CHECK_STATUS(res, goto error); |
169 | | |
170 | | /* Generate key. The policy's wrapper detects the prepend (via the |
171 | | * length mismatch in key1 vs the local ephemeral public key) and |
172 | | * performs the IKM chaining, deriving against the *previous* |
173 | | * accumulator (channel->currentIKM). The new accumulator is NOT |
174 | | * promoted here: the local- and remote-keys passes of one OPN must |
175 | | * both derive against the same previous accumulator, so the |
176 | | * advance to IKM_n happens exactly once, in generateRemoteKeys |
177 | | * (the last of the two passes). */ |
178 | 0 | res = sp->generateKey(sp, cc, &secretInput, &seedInput, &derived); |
179 | 0 | UA_CHECK_STATUS(res, goto error); |
180 | | |
181 | | /* Set the channel context */ |
182 | 0 | res |= sp->setLocalSymSigningKey(sp, cc, &localSigningKey); |
183 | 0 | res |= sp->setLocalSymEncryptingKey(sp, cc, &localEncryptingKey); |
184 | 0 | res |= sp->setLocalSymIv(sp, cc, &localIv); |
185 | |
|
186 | 0 | error: |
187 | 0 | if(res != UA_STATUSCODE_GOOD) { |
188 | 0 | UA_LOG_ERROR_CHANNEL(sp->logger, channel, |
189 | 0 | "Could not generate local keys (%s)", |
190 | 0 | UA_StatusCode_name(res)); |
191 | 0 | } |
192 | 0 | UA_ByteString_clear(&buf); |
193 | 0 | UA_ByteString_clear(&secretCombined); |
194 | 0 | return res; |
195 | 0 | } |
196 | | |
197 | | UA_StatusCode |
198 | 0 | generateRemoteKeys(UA_SecureChannel *channel) { |
199 | 0 | const UA_SecurityPolicy *sp = channel->securityPolicy; |
200 | 0 | UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR); |
201 | 0 | UA_LOG_DEBUG_CHANNEL(sp->logger, channel, "Generating new remote keys"); |
202 | |
|
203 | 0 | void *cc = channel->channelContext; |
204 | 0 | const UA_SecurityPolicyEncryptionAlgorithm *ea = &sp->symEncryptionAlgorithm; |
205 | | |
206 | | /* Generate symmetric key buffer of the required length. For AEAD ciphers |
207 | | * the IV length differs from the block size, so use getLocalIvLength when |
208 | | * available. */ |
209 | 0 | UA_ByteString buf; |
210 | 0 | size_t encrKL = ea->getRemoteKeyLength(sp, cc); |
211 | 0 | size_t encrBS = ea->getRemoteBlockSize(sp, cc); |
212 | 0 | size_t ivLen = ea->getLocalIvLength ? ea->getLocalIvLength(sp, cc) : encrBS; |
213 | 0 | size_t signKL = sp->symSignatureAlgorithm.getRemoteKeyLength(sp, cc); |
214 | 0 | if(ivLen + signKL + encrKL == 0) |
215 | 0 | return UA_STATUSCODE_GOOD; /* No keys to generate */ |
216 | | |
217 | 0 | UA_StatusCode res = UA_ByteString_allocBuffer(&buf, ivLen + signKL + encrKL); |
218 | 0 | UA_CHECK_STATUS(res, return res); |
219 | 0 | UA_ByteString remoteSigningKey = {signKL, buf.data}; |
220 | 0 | UA_ByteString remoteEncryptingKey = {encrKL, &buf.data[signKL]}; |
221 | 0 | UA_ByteString remoteIv = {ivLen, &buf.data[signKL + encrKL]}; |
222 | 0 | memset(buf.data, 0, buf.length); |
223 | 0 | UA_ByteString derived = { |
224 | 0 | derivedKeyMaterialLength(channel, signKL, buf.length), buf.data}; |
225 | | |
226 | | /* Build the IKM-prefixed `secret` input. Both the local- and |
227 | | * remote-keys passes of one OPN derive against the *same* previous |
228 | | * accumulator (channel->currentIKM); generateLocalKeys deliberately |
229 | | * did not advance it. The `seed` arg is passed unchanged — the |
230 | | * helper uses it as the alternate ephemeral public key candidate |
231 | | * and as part of the salt, so the prepend must not appear there. */ |
232 | 0 | UA_ByteString secretInput, seedInput = channel->remoteNonce; |
233 | 0 | UA_ByteString secretCombined = UA_BYTESTRING_NULL; |
234 | 0 | res = prepareKeyInput(channel, &channel->localNonce, |
235 | 0 | &secretInput, &secretCombined); |
236 | 0 | UA_CHECK_STATUS(res, goto error); |
237 | | |
238 | | /* Generate key. The policy's wrapper XORs the previous accumulator |
239 | | * with the new shared secret and writes the result (IKM_n) back |
240 | | * into secretCombined. */ |
241 | 0 | res = sp->generateKey(sp, cc, &secretInput, &seedInput, &derived); |
242 | 0 | UA_CHECK_STATUS(res, goto error); |
243 | | |
244 | | /* This is the last derivation of the OPN: promote the just-updated |
245 | | * IKM slot into channel->currentIKM so the next renewal chains from |
246 | | * IKM_n. (On the first OPN currentIKM was empty, so IKM_0 == the raw |
247 | | * shared secret for both passes — matching the spec's "no chaining |
248 | | * on the first OpenSecureChannel".) */ |
249 | 0 | res = captureIKMSlot(channel, &secretCombined); |
250 | 0 | if(res != UA_STATUSCODE_GOOD) { |
251 | 0 | res = UA_STATUSCODE_BADOUTOFMEMORY; |
252 | 0 | goto error; |
253 | 0 | } |
254 | | |
255 | | /* Set the channel context */ |
256 | 0 | res |= sp->setRemoteSymSigningKey(sp, cc, &remoteSigningKey); |
257 | 0 | res |= sp->setRemoteSymEncryptingKey(sp, cc, &remoteEncryptingKey); |
258 | 0 | res |= sp->setRemoteSymIv(sp, cc, &remoteIv); |
259 | |
|
260 | 0 | error: |
261 | 0 | if(res != UA_STATUSCODE_GOOD) { |
262 | 0 | UA_LOG_ERROR_CHANNEL(sp->logger, channel, |
263 | 0 | "Could not generate remote keys (%s)", |
264 | 0 | UA_StatusCode_name(res)); |
265 | 0 | } |
266 | 0 | UA_ByteString_clear(&buf); |
267 | 0 | UA_ByteString_clear(&secretCombined); |
268 | 0 | return res; |
269 | 0 | } |
270 | | |
271 | | /* v1.05.07 channel-bound SignatureData (SecureChannelEnhancements): the |
272 | | * CreateSession / ActivateSession signatures are bound to the SecureChannel by |
273 | | * prepending the ChannelThumbprint and including certificate hashes (not the |
274 | | * raw certs). */ |
275 | | |
276 | | /* The certificate hash is provided by the crypto backend via the global |
277 | | * UA_SecurityPolicy_hashCertificate (the algorithm is derived from the policy |
278 | | * URI). Wrapped here so this file links without a crypto backend - the |
279 | | * builders below are only reached at runtime for enhanced-security policies, |
280 | | * which only exist when encryption is enabled. */ |
281 | | #ifdef UA_ENABLE_ENCRYPTION |
282 | | static UA_StatusCode |
283 | | hashCert(const UA_SecurityPolicy *sp, const UA_ByteString *cert, |
284 | 0 | UA_ByteString *hash) { |
285 | 0 | return UA_SecurityPolicy_hashCertificate(sp, cert, hash); |
286 | 0 | } |
287 | | #else |
288 | | static UA_StatusCode |
289 | | hashCert(const UA_SecurityPolicy *sp, const UA_ByteString *cert, |
290 | | UA_ByteString *hash) { |
291 | | (void)sp; (void)cert; (void)hash; |
292 | | return UA_STATUSCODE_BADINTERNALERROR; |
293 | | } |
294 | | #endif |
295 | | |
296 | | /* Assemble a channel-bound SignatureData (OPC UA Part 6 v1.05.07, |
297 | | * SecureChannelEnhancements). All three share the shape |
298 | | * channelThumbprint | nonceA | H(cert_0) .. H(cert_n-1) | nonceB |
299 | | * and differ only in which certificate hashes appear and the nonce order: |
300 | | * |
301 | | * CreateSession ServerSignature (server signs, client verifies): |
302 | | * TP | clientNonce | H(serverChannelCert) | H(clientChannelCert) | serverNonce |
303 | | * ActivateSession ClientSignature (client signs, server verifies): |
304 | | * TP | serverNonce | H(serverAppCert) | H(serverChannelCert) | |
305 | | * H(clientChannelCert) | clientNonce |
306 | | * ActivateSession user-token sig (client signs w/ user key, server verifies): |
307 | | * TP | serverNonce | H(serverAppCert) | H(serverChannelCert) | |
308 | | * H(clientAppCert) | H(clientChannelCert) | clientNonce |
309 | | * |
310 | | * H() = the policy's curve hash of the leaf DER. Both peers must produce the |
311 | | * SAME bytes, so each side maps the logical certificate roles onto its own |
312 | | * local vs. remote view (the certs are channel-scoped: app == channel cert in |
313 | | * open62541, hence the duplicated hashes). The user/X.509-token certificate is |
314 | | * NOT part of the signed data (it is conveyed and validated separately). |
315 | | * |
316 | | * logical cert role server passes client passes |
317 | | * -------------------------------------------------------------------------- |
318 | | * server App / Channel sp->localCertificate channel->remoteCertificate |
319 | | * client App / Channel channel->remoteCertificate sp->localCertificate |
320 | | * |
321 | | * serverNonce = the session ServerNonce, clientNonce = the session |
322 | | * ClientNonce (the same value on both sides). */ |
323 | 0 | #define UA_MAX_SIGDATA_CERTS 4 |
324 | | static UA_StatusCode |
325 | | buildChannelBoundSignatureData(const UA_SecureChannel *channel, |
326 | | const UA_ByteString *firstNonce, |
327 | | const UA_ByteString *const *certs, size_t certCount, |
328 | 0 | const UA_ByteString *lastNonce, UA_ByteString *out) { |
329 | 0 | const UA_SecurityPolicy *sp = channel->securityPolicy; |
330 | 0 | if(!sp || !channel->enhancedSecurity || certCount > UA_MAX_SIGDATA_CERTS || |
331 | 0 | channel->channelThumbprint.length == 0) |
332 | 0 | return UA_STATUSCODE_BADINTERNALERROR; |
333 | | |
334 | | /* Hash the certificates. The inputs may be DER chains (e.g. the OPN |
335 | | * SenderCertificate stored in remoteCertificate), so hash only the leaf - |
336 | | * independent of how a given crypto backend's hashCert handles a chain. */ |
337 | 0 | UA_ByteString hashes[UA_MAX_SIGDATA_CERTS]; |
338 | 0 | for(size_t i = 0; i < UA_MAX_SIGDATA_CERTS; i++) |
339 | 0 | hashes[i] = UA_BYTESTRING_NULL; |
340 | 0 | UA_StatusCode res = UA_STATUSCODE_GOOD; |
341 | 0 | size_t hashesLen = 0; |
342 | 0 | for(size_t i = 0; i < certCount && res == UA_STATUSCODE_GOOD; i++) { |
343 | 0 | UA_ByteString leaf = getLeafCertificate(*certs[i]); |
344 | 0 | res = hashCert(sp, &leaf, &hashes[i]); |
345 | 0 | hashesLen += hashes[i].length; |
346 | 0 | } |
347 | 0 | if(res != UA_STATUSCODE_GOOD) |
348 | 0 | goto cleanup; |
349 | | |
350 | | /* channelThumbprint | firstNonce | hashes | lastNonce */ |
351 | 0 | const UA_ByteString *tp = &channel->channelThumbprint; |
352 | 0 | res = UA_ByteString_allocBuffer(out, tp->length + firstNonce->length + |
353 | 0 | hashesLen + lastNonce->length); |
354 | 0 | if(res != UA_STATUSCODE_GOOD) |
355 | 0 | goto cleanup; |
356 | | |
357 | 0 | size_t o = 0; |
358 | 0 | memcpy(out->data + o, tp->data, tp->length); o += tp->length; |
359 | 0 | memcpy(out->data + o, firstNonce->data, firstNonce->length); o += firstNonce->length; |
360 | 0 | for(size_t i = 0; i < certCount; i++) { |
361 | 0 | memcpy(out->data + o, hashes[i].data, hashes[i].length); |
362 | 0 | o += hashes[i].length; |
363 | 0 | } |
364 | 0 | memcpy(out->data + o, lastNonce->data, lastNonce->length); |
365 | |
|
366 | 0 | cleanup: |
367 | 0 | for(size_t i = 0; i < certCount; i++) |
368 | 0 | UA_ByteString_clear(&hashes[i]); |
369 | 0 | return res; |
370 | 0 | } |
371 | | |
372 | | /* CreateSession ServerSignature (see the layout table above). */ |
373 | | UA_StatusCode |
374 | | UA_SecureChannel_buildCreateSessionSignatureData( |
375 | | const UA_SecureChannel *channel, const UA_ByteString *clientNonce, |
376 | | const UA_ByteString *serverNonce, const UA_ByteString *serverChannelCert, |
377 | 0 | const UA_ByteString *clientChannelCert, UA_ByteString *out) { |
378 | 0 | const UA_ByteString *certs[] = {serverChannelCert, clientChannelCert}; |
379 | 0 | return buildChannelBoundSignatureData(channel, clientNonce, certs, 2, |
380 | 0 | serverNonce, out); |
381 | 0 | } |
382 | | |
383 | | /* ActivateSession ClientSignature (see the layout table above). */ |
384 | | UA_StatusCode |
385 | | UA_SecureChannel_buildActivateSessionSignatureData( |
386 | | const UA_SecureChannel *channel, const UA_ByteString *serverNonce, |
387 | | const UA_ByteString *clientNonce, const UA_ByteString *serverAppCert, |
388 | | const UA_ByteString *serverChannelCert, const UA_ByteString *clientChannelCert, |
389 | 0 | UA_ByteString *out) { |
390 | 0 | const UA_ByteString *certs[] = {serverAppCert, serverChannelCert, clientChannelCert}; |
391 | 0 | return buildChannelBoundSignatureData(channel, serverNonce, certs, 3, |
392 | 0 | clientNonce, out); |
393 | 0 | } |
394 | | |
395 | | /* ActivateSession X.509 user-token signature (see the layout table above). */ |
396 | | UA_StatusCode |
397 | | UA_SecureChannel_buildUserTokenSignatureData( |
398 | | const UA_SecureChannel *channel, const UA_ByteString *serverNonce, |
399 | | const UA_ByteString *clientNonce, const UA_ByteString *serverAppCert, |
400 | | const UA_ByteString *serverChannelCert, const UA_ByteString *clientAppCert, |
401 | 0 | const UA_ByteString *clientChannelCert, UA_ByteString *out) { |
402 | 0 | const UA_ByteString *certs[] = {serverAppCert, serverChannelCert, |
403 | 0 | clientAppCert, clientChannelCert}; |
404 | 0 | return buildChannelBoundSignatureData(channel, serverNonce, certs, 4, |
405 | 0 | clientNonce, out); |
406 | 0 | } |
407 | | |
408 | | /***************************/ |
409 | | /* Send Asymmetric Message */ |
410 | | /***************************/ |
411 | | |
412 | | /* The length of the static header content */ |
413 | 224 | #define UA_SECURECHANNEL_ASYMMETRIC_SECURITYHEADER_FIXED_LENGTH 12 |
414 | | |
415 | | size_t |
416 | 224 | calculateAsymAlgSecurityHeaderLength(const UA_SecureChannel *channel) { |
417 | 224 | const UA_SecurityPolicy *sp = channel->securityPolicy; |
418 | 224 | UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR); |
419 | | |
420 | 224 | size_t asymHeaderLength = UA_SECURECHANNEL_ASYMMETRIC_SECURITYHEADER_FIXED_LENGTH; |
421 | 224 | if(sp->policyUri.length > SIZE_MAX - asymHeaderLength) |
422 | 0 | return SIZE_MAX; |
423 | 224 | asymHeaderLength += sp->policyUri.length; |
424 | 224 | if(channel->securityMode == UA_MESSAGESECURITYMODE_NONE) |
425 | 224 | return asymHeaderLength; |
426 | | |
427 | | /* OPN is always encrypted even if the mode is sign only */ |
428 | 0 | if(asymHeaderLength > SIZE_MAX - 20) |
429 | 0 | return SIZE_MAX; |
430 | 0 | asymHeaderLength += 20; /* Thumbprints are always 20 byte long */ |
431 | 0 | if(sp->localCertificate.length > SIZE_MAX - asymHeaderLength) |
432 | 0 | return SIZE_MAX; |
433 | 0 | asymHeaderLength += sp->localCertificate.length; |
434 | 0 | return asymHeaderLength; |
435 | 0 | } |
436 | | |
437 | | UA_StatusCode |
438 | | prependHeadersAsym(UA_SecureChannel *const channel, UA_Byte *header_pos, |
439 | | const UA_Byte *buf_end, size_t totalLength, |
440 | | size_t securityHeaderLength, UA_UInt32 requestId, |
441 | 112 | size_t *const encryptedLength) { |
442 | 112 | const UA_SecurityPolicy *sp = channel->securityPolicy; |
443 | 112 | UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR); |
444 | | |
445 | 112 | void *cc = channel->channelContext; |
446 | | |
447 | 112 | *encryptedLength = totalLength; |
448 | 112 | if(channel->securityMode != UA_MESSAGESECURITYMODE_NONE) { |
449 | 0 | size_t dataToEncryptLength = totalLength - |
450 | 0 | (UA_SECURECHANNEL_CHANNELHEADER_LENGTH + securityHeaderLength); |
451 | 0 | size_t plainTextBlockSize = sp->asymEncryptionAlgorithm. |
452 | 0 | getRemotePlainTextBlockSize(sp, cc); |
453 | 0 | size_t encryptedBlockSize = sp->asymEncryptionAlgorithm. |
454 | 0 | getRemoteBlockSize(sp, cc); |
455 | | |
456 | | /* Padding always fills up the last block */ |
457 | 0 | UA_assert(plainTextBlockSize > 0); |
458 | 0 | UA_assert(dataToEncryptLength % plainTextBlockSize == 0); |
459 | 0 | size_t blocks = dataToEncryptLength / plainTextBlockSize; |
460 | 0 | *encryptedLength = totalLength + blocks * (encryptedBlockSize - plainTextBlockSize); |
461 | 0 | } |
462 | | |
463 | 112 | UA_TcpMessageHeader messageHeader; |
464 | 112 | messageHeader.messageTypeAndChunkType = UA_MESSAGETYPE_OPN + UA_CHUNKTYPE_FINAL; |
465 | 112 | messageHeader.messageSize = (UA_UInt32)*encryptedLength; |
466 | 112 | UA_UInt32 secureChannelId = channel->securityToken.channelId; |
467 | 112 | UA_StatusCode res = UA_STATUSCODE_GOOD; |
468 | 112 | res |= UA_encodeBinaryInternal(&messageHeader, |
469 | 112 | &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER], |
470 | 112 | &header_pos, &buf_end, NULL, NULL, NULL); |
471 | 112 | res |= UA_UInt32_encodeBinary(&secureChannelId, &header_pos, buf_end); |
472 | 112 | UA_CHECK_STATUS(res, return res); |
473 | | |
474 | 112 | UA_AsymmetricAlgorithmSecurityHeader asymHeader; |
475 | 112 | UA_AsymmetricAlgorithmSecurityHeader_init(&asymHeader); |
476 | 112 | asymHeader.securityPolicyUri = sp->policyUri; |
477 | 112 | if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN || |
478 | 112 | channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) { |
479 | 0 | asymHeader.senderCertificate = sp->localCertificate; |
480 | 0 | asymHeader.receiverCertificateThumbprint.length = 20; |
481 | 0 | asymHeader.receiverCertificateThumbprint.data = channel->remoteCertificateThumbprint; |
482 | 0 | } |
483 | 112 | res = UA_encodeBinaryInternal(&asymHeader, |
484 | 112 | &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER], |
485 | 112 | &header_pos, &buf_end, NULL, NULL, NULL); |
486 | 112 | UA_CHECK_STATUS(res, return res); |
487 | | |
488 | 112 | UA_SequenceHeader seqHeader; |
489 | 112 | seqHeader.requestId = requestId; |
490 | 112 | seqHeader.sequenceNumber = UA_SecureChannel_nextSequenceNumber(channel); |
491 | 112 | res = UA_encodeBinaryInternal(&seqHeader, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER], |
492 | 112 | &header_pos, &buf_end, NULL, NULL, NULL); |
493 | 112 | return res; |
494 | 112 | } |
495 | | |
496 | | UA_StatusCode |
497 | | hideBytesAsym(const UA_SecureChannel *channel, UA_Byte **buf_start, |
498 | 112 | const UA_Byte **buf_end) { |
499 | 112 | UA_Byte *const bufferStart = *buf_start; |
500 | 112 | const size_t bufferLength = (size_t)(*buf_end - bufferStart); |
501 | | |
502 | | /* Check the complete unencrypted header before constructing pointers into |
503 | | * the payload. The certificate is already constrained by the negotiated |
504 | | * send-buffer size; it does not need a separate policy limit. */ |
505 | 112 | const size_t asymHeaderLength = calculateAsymAlgSecurityHeaderLength(channel); |
506 | 112 | if(asymHeaderLength > bufferLength || |
507 | 112 | UA_SECURECHANNEL_CHANNELHEADER_LENGTH > bufferLength - asymHeaderLength) |
508 | 0 | return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED; |
509 | 112 | const size_t headerLength = |
510 | 112 | UA_SECURECHANNEL_CHANNELHEADER_LENGTH + asymHeaderLength; |
511 | 112 | if(UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH > bufferLength - headerLength) |
512 | 0 | return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED; |
513 | | |
514 | 112 | const size_t payloadOffset = |
515 | 112 | headerLength + UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH; |
516 | | |
517 | 112 | if(channel->securityMode == UA_MESSAGESECURITYMODE_NONE) { |
518 | 112 | *buf_start = bufferStart + payloadOffset; |
519 | 112 | return UA_STATUSCODE_GOOD; |
520 | 112 | } |
521 | | |
522 | | /* Determine how many complete encrypted blocks fit into the chunk. */ |
523 | 0 | const UA_SecurityPolicy *sp = channel->securityPolicy; |
524 | 0 | UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR); |
525 | 0 | void *cc = channel->channelContext; |
526 | | |
527 | | /* Block sizes depend on the remote key (certificate) */ |
528 | 0 | const size_t plainTextBlockSize = |
529 | 0 | sp->asymEncryptionAlgorithm.getRemotePlainTextBlockSize(sp, cc); |
530 | 0 | const size_t encryptedBlockSize = |
531 | 0 | sp->asymEncryptionAlgorithm.getRemoteBlockSize(sp, cc); |
532 | 0 | if(plainTextBlockSize == 0 || encryptedBlockSize == 0) |
533 | 0 | return UA_STATUSCODE_BADINTERNALERROR; |
534 | 0 | const UA_Boolean extraPadding = |
535 | 0 | (sp->asymEncryptionAlgorithm.getRemoteKeyLength(sp, cc) > 2048); |
536 | |
|
537 | 0 | const size_t maxEncrypted = bufferLength - headerLength; |
538 | 0 | const size_t maxBlocks = maxEncrypted / encryptedBlockSize; |
539 | 0 | if(maxBlocks > SIZE_MAX / plainTextBlockSize) |
540 | 0 | return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED; |
541 | 0 | const size_t maxPlaintext = maxBlocks * plainTextBlockSize; |
542 | | |
543 | | /* The encrypted plaintext also contains the SequenceHeader, signature and |
544 | | * at least one padding-size byte. */ |
545 | 0 | const size_t signatureSize = |
546 | 0 | sp->asymSignatureAlgorithm.getLocalSignatureSize(sp, cc); |
547 | 0 | const size_t paddingBytes = (UA_LIKELY(!extraPadding)) ? 1u : 2u; |
548 | 0 | const size_t fixedOverhead = |
549 | 0 | UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH + paddingBytes; |
550 | 0 | if(signatureSize > SIZE_MAX - fixedOverhead) |
551 | 0 | return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED; |
552 | 0 | const size_t payloadOverhead = fixedOverhead + signatureSize; |
553 | 0 | if(maxPlaintext < payloadOverhead) |
554 | 0 | return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED; |
555 | | |
556 | 0 | const size_t payloadCapacity = maxPlaintext - payloadOverhead; |
557 | 0 | if(payloadCapacity > bufferLength - payloadOffset) |
558 | 0 | return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED; |
559 | 0 | *buf_end = bufferStart + payloadOffset + payloadCapacity; |
560 | |
|
561 | 0 | *buf_start = bufferStart + payloadOffset; |
562 | 0 | return UA_STATUSCODE_GOOD; |
563 | 0 | } |
564 | | |
565 | | /* Assumes that pos can be advanced to the end of the current block */ |
566 | | void |
567 | | padChunk(UA_SecureChannel *channel, |
568 | | const UA_SecurityPolicySignatureAlgorithm *sa, |
569 | | const UA_SecurityPolicyEncryptionAlgorithm *ea, |
570 | 0 | const UA_Byte *start, UA_Byte **pos) { |
571 | 0 | UA_SecurityPolicy *sp = channel->securityPolicy; |
572 | 0 | void *cc = channel->channelContext; |
573 | |
|
574 | 0 | const size_t bytesToWrite = (uintptr_t)*pos - (uintptr_t)start; |
575 | |
|
576 | 0 | size_t signatureSize = sa->getLocalSignatureSize(sp, cc); |
577 | 0 | size_t plainTextBlockSize = ea->getRemotePlainTextBlockSize(sp, cc); |
578 | 0 | UA_Boolean extraPadding = (ea->getRemoteKeyLength(sp, cc) > 2048); |
579 | 0 | size_t paddingBytes = (UA_LIKELY(!extraPadding)) ? 1u : 2u; |
580 | |
|
581 | 0 | UA_assert(plainTextBlockSize > 0); |
582 | 0 | size_t lastBlock = ((bytesToWrite + signatureSize + paddingBytes) % plainTextBlockSize); |
583 | 0 | size_t paddingLength = (lastBlock != 0) ? plainTextBlockSize - lastBlock : 0; |
584 | |
|
585 | 0 | UA_assert((bytesToWrite + signatureSize + |
586 | 0 | paddingBytes + paddingLength) % plainTextBlockSize == 0); |
587 | | |
588 | 0 | UA_LOG_TRACE_CHANNEL(sp->logger, channel, |
589 | 0 | "Add %lu bytes of padding plus %lu padding size bytes", |
590 | 0 | (long unsigned int)paddingLength, |
591 | 0 | (long unsigned int)paddingBytes); |
592 | | |
593 | | /* Write the padding. This is <= because the paddingSize byte also has to be |
594 | | * written */ |
595 | 0 | UA_Byte paddingByte = (UA_Byte)paddingLength; |
596 | 0 | for(size_t i = 0; i <= paddingLength; ++i) { |
597 | 0 | **pos = paddingByte; |
598 | 0 | ++*pos; |
599 | 0 | } |
600 | | |
601 | | /* Write the extra padding byte if required */ |
602 | 0 | if(extraPadding) { |
603 | 0 | **pos = (UA_Byte)(paddingLength >> 8u); |
604 | 0 | ++*pos; |
605 | 0 | } |
606 | 0 | } |
607 | | |
608 | | UA_StatusCode |
609 | | signAndEncryptAsym(UA_SecureChannel *channel, size_t preSignLength, |
610 | | UA_ByteString *buf, size_t securityHeaderLength, |
611 | 112 | size_t totalLength) { |
612 | 112 | if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGN && |
613 | 112 | channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) |
614 | 112 | return UA_STATUSCODE_GOOD; |
615 | | |
616 | 0 | const UA_SecurityPolicy *sp = channel->securityPolicy; |
617 | 0 | void *cc = channel->channelContext; |
618 | | |
619 | | /* OPC UA Part 6 v1.05.07 §6.7.5 "ChannelThumbprint" (enhanced policies, |
620 | | * FIRST OPN only — an empty channelThumbprint identifies the first OPN; NOT |
621 | | * on renewals. The OPN response signature is extended with the first OPN |
622 | | * request signature: the client (request side) stores its just-computed |
623 | | * signature for the later response verify; the server (response side) |
624 | | * appends the request signature captured by decryptAndVerifyChunk to the |
625 | | * data being signed. */ |
626 | 0 | UA_Boolean firstOPN = (channel->enhancedSecurity && |
627 | 0 | channel->channelThumbprint.length == 0); |
628 | 0 | UA_ByteString *appendSig = NULL; |
629 | 0 | if(firstOPN && channel->firstRequestSignature.length > 0) |
630 | 0 | appendSig = &channel->firstRequestSignature; /* server: extend signed data */ |
631 | |
|
632 | 0 | size_t sigsize = sp->asymSignatureAlgorithm.getLocalSignatureSize(sp, cc); |
633 | | |
634 | | /* Prepare the data to sign. If we need to append the request |
635 | | * signature, build a contiguous buffer [body | requestSig] and sign |
636 | | * that. Otherwise sign the body in-place. */ |
637 | 0 | UA_ByteString signature = {sigsize, buf->data + preSignLength}; |
638 | 0 | UA_StatusCode retval; |
639 | |
|
640 | 0 | if(appendSig) { |
641 | 0 | size_t bodyLen = preSignLength; |
642 | 0 | size_t extLen = bodyLen + appendSig->length; |
643 | 0 | UA_Byte *ext = (UA_Byte*)UA_malloc(extLen); |
644 | 0 | if(!ext) |
645 | 0 | return UA_STATUSCODE_BADOUTOFMEMORY; |
646 | 0 | memcpy(ext, buf->data, bodyLen); |
647 | 0 | memcpy(ext + bodyLen, appendSig->data, appendSig->length); |
648 | 0 | UA_ByteString dataToSignExt = {extLen, ext}; |
649 | 0 | retval = sp->asymSignatureAlgorithm.sign(sp, cc, &dataToSignExt, &signature); |
650 | 0 | UA_free(ext); |
651 | 0 | } else { |
652 | 0 | const UA_ByteString dataToSign = {preSignLength, buf->data}; |
653 | 0 | retval = sp->asymSignatureAlgorithm.sign(sp, cc, &dataToSign, &signature); |
654 | | /* First-OPN client side: remember the just-computed request |
655 | | * signature. The verify path on the client will use it to |
656 | | * extend the response body. */ |
657 | 0 | if(retval == UA_STATUSCODE_GOOD && firstOPN && signature.length > 0) { |
658 | 0 | UA_StatusCode clip = |
659 | 0 | UA_ByteString_copy(&signature, &channel->firstRequestSignature); |
660 | 0 | if(clip != UA_STATUSCODE_GOOD) |
661 | 0 | retval = clip; |
662 | 0 | } |
663 | 0 | } |
664 | | |
665 | 0 | UA_CHECK_STATUS(retval, return retval); |
666 | | |
667 | | /* Server, first OPN response (appendSig != NULL): the just-computed |
668 | | * signature is the ChannelThumbprint - capture it (preserved across renewals |
669 | | * to bind the session SignatureData) and release the consumed request |
670 | | * signature. (The client stored its request signature above; that copy is |
671 | | * released later by the OPN-response verify.) */ |
672 | 0 | if(appendSig != NULL) { |
673 | 0 | UA_StatusCode tp = UA_ByteString_copy(&signature, &channel->channelThumbprint); |
674 | 0 | UA_CHECK_STATUS(tp, return tp); |
675 | 0 | UA_ByteString_clear(&channel->firstRequestSignature); |
676 | 0 | } |
677 | | |
678 | | /* Specification part 6, 6.7.4: The OpenSecureChannel Messages are |
679 | | * signed and encrypted if the SecurityMode is not None (even if the |
680 | | * SecurityMode is SignOnly). */ |
681 | 0 | size_t unencrypted_length = |
682 | 0 | UA_SECURECHANNEL_CHANNELHEADER_LENGTH + securityHeaderLength; |
683 | 0 | UA_ByteString dataToEncrypt = |
684 | 0 | {totalLength - unencrypted_length, &buf->data[unencrypted_length]}; |
685 | 0 | return sp->asymEncryptionAlgorithm.encrypt(sp, cc, &dataToEncrypt); |
686 | 0 | } |
687 | | |
688 | | /**************************/ |
689 | | /* Send Symmetric Message */ |
690 | | /**************************/ |
691 | | |
692 | | UA_StatusCode |
693 | | signAndEncryptSym(UA_MessageContext *messageContext, |
694 | 4.62k | size_t preSigLength, size_t totalLength) { |
695 | 4.62k | const UA_SecureChannel *channel = messageContext->channel; |
696 | 4.62k | if(channel->securityMode == UA_MESSAGESECURITYMODE_NONE) |
697 | 4.62k | return UA_STATUSCODE_GOOD; |
698 | | |
699 | 0 | const UA_SecurityPolicy *sp = channel->securityPolicy; |
700 | 0 | void *cc = channel->channelContext; |
701 | | |
702 | | /* For AEAD policies (ChaCha20-Poly1305), set the message security |
703 | | * parameters for nonce masking. Then let the encrypt callback handle |
704 | | * both authentication and encryption. */ |
705 | 0 | if(UA_SecurityPolicy_isAead(sp)) { |
706 | | /* Set AEAD parameters: tokenId, previous seqNo, AAD */ |
707 | 0 | if(sp->setMessageSecurityParameters) { |
708 | 0 | UA_ByteString aad; |
709 | 0 | aad.data = messageContext->messageBuffer.data; |
710 | 0 | aad.length = UA_SECURECHANNEL_CHANNELHEADER_LENGTH + |
711 | 0 | UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH; |
712 | | /* The AEAD nonce is masked with the PREVIOUS sequence number: the |
713 | | * receiver masks with its receiveSequenceNumber, which is still the |
714 | | * prior chunk's number at decrypt time (incremented only after |
715 | | * decryption). sendSequenceNumber is the post-increment counter, so |
716 | | * the value just emitted is (sendSequenceNumber - 1) and the |
717 | | * previous one is (sendSequenceNumber - 2). ECC_AEAD always uses the |
718 | | * non-legacy counter (first emitted number is 0). */ |
719 | 0 | UA_UInt32 prevSeqNo = channel->sendSequenceNumber >= 2 ? |
720 | 0 | (UA_UInt32)(channel->sendSequenceNumber - 2) : 0; |
721 | 0 | UA_StatusCode res = sp->setMessageSecurityParameters( |
722 | 0 | sp, cc, channel->securityToken.tokenId, prevSeqNo, &aad); |
723 | 0 | UA_CHECK_STATUS(res, return res); |
724 | 0 | } |
725 | | |
726 | 0 | if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) { |
727 | | /* Full AEAD: encrypt + compute auth tag. Data includes |
728 | | * the 16-byte tag space at the end. */ |
729 | 0 | UA_ByteString dataToProcess; |
730 | 0 | dataToProcess.data = messageContext->messageBuffer.data + |
731 | 0 | UA_SECURECHANNEL_CHANNELHEADER_LENGTH + |
732 | 0 | UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH; |
733 | 0 | dataToProcess.length = totalLength - |
734 | 0 | (UA_SECURECHANNEL_CHANNELHEADER_LENGTH + |
735 | 0 | UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH); |
736 | 0 | return sp->symEncryptionAlgorithm.encrypt(sp, cc, &dataToProcess); |
737 | 0 | } |
738 | | |
739 | | /* Sign-only: Compute Poly1305 auth tag */ |
740 | 0 | UA_ByteString dataToSign = messageContext->messageBuffer; |
741 | 0 | dataToSign.length = preSigLength; |
742 | 0 | UA_ByteString signature; |
743 | 0 | signature.length = |
744 | 0 | sp->symSignatureAlgorithm.getLocalSignatureSize(sp, cc); |
745 | 0 | signature.data = messageContext->buf_pos; |
746 | 0 | return sp->symSignatureAlgorithm. |
747 | 0 | sign(sp, cc, &dataToSign, &signature); |
748 | 0 | } |
749 | | |
750 | | /* Sign */ |
751 | 0 | UA_ByteString dataToSign = messageContext->messageBuffer; |
752 | 0 | dataToSign.length = preSigLength; |
753 | 0 | UA_ByteString signature; |
754 | 0 | signature.length = |
755 | 0 | sp->symSignatureAlgorithm.getLocalSignatureSize(sp, cc); |
756 | 0 | signature.data = messageContext->buf_pos; |
757 | 0 | UA_StatusCode res = sp->symSignatureAlgorithm. |
758 | 0 | sign(sp, cc, &dataToSign, &signature); |
759 | 0 | UA_CHECK_STATUS(res, return res); |
760 | | |
761 | 0 | if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) |
762 | 0 | return UA_STATUSCODE_GOOD; |
763 | | |
764 | | /* Encrypt */ |
765 | 0 | UA_ByteString dataToEncrypt; |
766 | 0 | dataToEncrypt.data = messageContext->messageBuffer.data + |
767 | 0 | UA_SECURECHANNEL_CHANNELHEADER_LENGTH + |
768 | 0 | UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH; |
769 | 0 | dataToEncrypt.length = totalLength - |
770 | 0 | (UA_SECURECHANNEL_CHANNELHEADER_LENGTH + |
771 | 0 | UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH); |
772 | 0 | return sp->symEncryptionAlgorithm.encrypt(sp, cc, &dataToEncrypt); |
773 | 0 | } |
774 | | |
775 | | void |
776 | 4.62k | setBufPos(UA_MessageContext *mc) { |
777 | | /* Forward the data pointer so that the payload is encoded after the message |
778 | | * header. This has to be a symmetric message because OPN (with asymmetric |
779 | | * encryption) does not support chunking. */ |
780 | 4.62k | mc->buf_pos = &mc->messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH]; |
781 | 4.62k | mc->buf_end = &mc->messageBuffer.data[mc->messageBuffer.length]; |
782 | | |
783 | 4.62k | if(mc->channel->securityMode == UA_MESSAGESECURITYMODE_NONE) |
784 | 4.62k | return; |
785 | | |
786 | 0 | const UA_SecureChannel *channel = mc->channel; |
787 | 0 | const UA_SecurityPolicy *sp = channel->securityPolicy; |
788 | 0 | void *cc = channel->channelContext; |
789 | | |
790 | | /* For AEAD (ChaCha20-Poly1305): no padding, no block alignment. |
791 | | * Only reserve space for the authentication tag (signature size). */ |
792 | 0 | if(UA_SecurityPolicy_isAead(sp)) { |
793 | 0 | size_t sigsize = |
794 | 0 | sp->symSignatureAlgorithm.getLocalSignatureSize(sp, cc); |
795 | 0 | mc->buf_end -= sigsize; |
796 | 0 | UA_LOG_TRACE_CHANNEL(sp->logger, channel, |
797 | 0 | "Prepare an AEAD symmetric message buffer of length %lu " |
798 | 0 | "with a usable maximum payload length of %lu", |
799 | 0 | (long unsigned)mc->messageBuffer.length, |
800 | 0 | (long unsigned)((uintptr_t)mc->buf_end - |
801 | 0 | (uintptr_t)mc->messageBuffer.data)); |
802 | 0 | return; |
803 | 0 | } |
804 | | |
805 | 0 | size_t sigsize = |
806 | 0 | sp->symSignatureAlgorithm.getLocalSignatureSize(sp, cc); |
807 | 0 | size_t plainBlockSize = |
808 | 0 | sp->symEncryptionAlgorithm.getRemotePlainTextBlockSize(sp, cc); |
809 | | |
810 | | /* Assuming that for symmetric encryption the plainTextBlockSize == |
811 | | * cypherTextBlockSize. For symmetric encryption the remote/local block |
812 | | * sizes are identical. */ |
813 | 0 | UA_assert(sp->symEncryptionAlgorithm.getRemoteBlockSize(sp, cc) == plainBlockSize); |
814 | | |
815 | | /* Leave enough space for the signature and padding */ |
816 | 0 | mc->buf_end -= sigsize; |
817 | 0 | UA_assert(plainBlockSize > 0); |
818 | 0 | mc->buf_end -= mc->messageBuffer.length % plainBlockSize; |
819 | |
|
820 | 0 | if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) { |
821 | | /* Reserve space for the padding bytes */ |
822 | 0 | UA_Boolean extraPadding = |
823 | 0 | (sp->symEncryptionAlgorithm.getRemoteKeyLength(sp, cc) > 2048); |
824 | 0 | mc->buf_end -= (UA_LIKELY(!extraPadding)) ? 1 : 2; |
825 | 0 | } |
826 | |
|
827 | 0 | UA_LOG_TRACE_CHANNEL(sp->logger, channel, |
828 | 0 | "Prepare a symmetric message buffer of length %lu " |
829 | 0 | "with a usable maximum payload length of %lu", |
830 | 0 | (long unsigned)mc->messageBuffer.length, |
831 | 0 | (long unsigned)((uintptr_t)mc->buf_end - |
832 | 0 | (uintptr_t)mc->messageBuffer.data)); |
833 | 0 | } |
834 | | |
835 | | /****************************/ |
836 | | /* Process a received Chunk */ |
837 | | /****************************/ |
838 | | |
839 | | static size_t |
840 | | decodePadding(const UA_SecureChannel *channel, |
841 | | const UA_SecurityPolicyEncryptionAlgorithm *encryptionAlgorithm, |
842 | 0 | const UA_ByteString *chunk, size_t sigsize) { |
843 | | /* Read the byte with the padding size */ |
844 | 0 | size_t paddingSize = chunk->data[chunk->length - sigsize - 1]; |
845 | | |
846 | | /* Extra padding size */ |
847 | 0 | if(encryptionAlgorithm->getLocalKeyLength(channel->securityPolicy, |
848 | 0 | channel->channelContext) > 2048) { |
849 | 0 | paddingSize <<= 8u; |
850 | 0 | paddingSize += chunk->data[chunk->length - sigsize - 2]; |
851 | 0 | paddingSize += 1; /* Extra padding byte itself */ |
852 | 0 | } |
853 | | |
854 | | /* Add one since the paddingSize byte itself needs to be removed as well */ |
855 | 0 | return paddingSize + 1; |
856 | 0 | } |
857 | | |
858 | | /* Sets the payload to a pointer inside the chunk buffer. Returns the requestId |
859 | | * and the sequenceNumber */ |
860 | | UA_StatusCode |
861 | | decryptAndVerifyChunk(UA_SecureChannel *channel, |
862 | | const UA_SecurityPolicySignatureAlgorithm *signatureAlgorithm, |
863 | | const UA_SecurityPolicyEncryptionAlgorithm *encryptionAlgorithm, |
864 | | UA_MessageType messageType, UA_ByteString *chunk, |
865 | 6.60k | size_t offset) { |
866 | 6.60k | UA_SecurityPolicy *sp = channel->securityPolicy; |
867 | 6.60k | void *cc = channel->channelContext; |
868 | 6.60k | UA_StatusCode res = UA_STATUSCODE_GOOD; |
869 | | |
870 | | /* AEAD path (ChaCha20-Poly1305): the decrypt callback handles both |
871 | | * decryption and authentication tag verification in one step. */ |
872 | 6.60k | if(UA_SecurityPolicy_isAead(sp) && |
873 | 0 | messageType != UA_MESSAGETYPE_OPN) { |
874 | | |
875 | | /* Set AEAD parameters before decrypt/verify. The masked nonce is keyed |
876 | | * on the TokenId of *this* message, which is taken from the chunk's |
877 | | * symmetric SecurityHeader (right after the 12-byte channel header) and |
878 | | * not from channel->securityToken: during a token rollover the peer may |
879 | | * still secure messages with the old token (Part 4 §5.5.2) while the |
880 | | * channel already holds the new token. Using the wrong TokenId here |
881 | | * makes the AEAD tag verification fail. */ |
882 | 0 | if(sp->setMessageSecurityParameters) { |
883 | 0 | UA_ByteString aad = {offset, chunk->data}; |
884 | 0 | size_t tokenOffset = UA_SECURECHANNEL_CHANNELHEADER_LENGTH; |
885 | 0 | UA_UInt32 msgTokenId = channel->securityToken.tokenId; |
886 | 0 | if(offset >= UA_SECURECHANNEL_MESSAGE_MIN_LENGTH) |
887 | 0 | UA_UInt32_decodeBinary(chunk, &tokenOffset, &msgTokenId); |
888 | 0 | res = sp->setMessageSecurityParameters( |
889 | 0 | sp, cc, msgTokenId, |
890 | 0 | channel->receiveSequenceNumber, &aad); |
891 | 0 | UA_CHECK_STATUS(res, return res); |
892 | 0 | } |
893 | | |
894 | 0 | if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) { |
895 | | /* Full AEAD decrypt + verify. The decrypt callback processes |
896 | | * the data including the 16-byte auth tag at the end. On |
897 | | * success, it reduces cipher.length by the tag size. */ |
898 | 0 | UA_ByteString cipher = {chunk->length - offset, chunk->data + offset}; |
899 | 0 | res = encryptionAlgorithm->decrypt(sp, cc, &cipher); |
900 | 0 | UA_CHECK_STATUS(res, |
901 | 0 | UA_LOG_WARNING_CHANNEL(sp->logger, channel, |
902 | 0 | "AEAD decryption/verification failed"); |
903 | 0 | return res); |
904 | 0 | chunk->length = cipher.length + offset; |
905 | 0 | } else if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN) { |
906 | | /* Sign-only: verify the auth tag without decryption */ |
907 | 0 | size_t sigsize = signatureAlgorithm->getRemoteSignatureSize(sp, cc); |
908 | 0 | UA_CHECK(sigsize < chunk->length, |
909 | 0 | return UA_STATUSCODE_BADSECURITYCHECKSFAILED); |
910 | 0 | const UA_ByteString content = {chunk->length - sigsize, chunk->data}; |
911 | 0 | const UA_ByteString sig = {sigsize, chunk->data + chunk->length - sigsize}; |
912 | 0 | res = signatureAlgorithm->verify(sp, cc, &content, &sig); |
913 | 0 | UA_CHECK_STATUS(res, |
914 | 0 | UA_LOG_WARNING_CHANNEL(sp->logger, channel, |
915 | 0 | "AEAD signature verification failed"); |
916 | 0 | return res); |
917 | 0 | chunk->length -= sigsize; |
918 | 0 | } |
919 | | |
920 | | /* Verify the content length */ |
921 | 0 | UA_CHECK(offset + 9 < chunk->length, |
922 | 0 | UA_LOG_ERROR_CHANNEL(sp->logger, channel, |
923 | 0 | "AEAD message too short"); |
924 | 0 | return UA_STATUSCODE_BADSECURITYCHECKSFAILED); |
925 | 0 | return UA_STATUSCODE_GOOD; |
926 | 0 | } |
927 | | |
928 | | /* Decrypt the chunk */ |
929 | 6.60k | if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT || |
930 | 6.60k | messageType == UA_MESSAGETYPE_OPN) { |
931 | 2.51k | UA_ByteString cipher = {chunk->length - offset, chunk->data + offset}; |
932 | 2.51k | res = encryptionAlgorithm->decrypt(sp, cc, &cipher); |
933 | 2.51k | UA_CHECK_STATUS(res, return res); |
934 | 2.51k | chunk->length = cipher.length + offset; |
935 | 2.51k | } |
936 | | |
937 | | /* Does the message have a signature? */ |
938 | 6.60k | if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGN && |
939 | 6.60k | channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT && |
940 | 6.60k | messageType != UA_MESSAGETYPE_OPN) |
941 | 4.09k | return UA_STATUSCODE_GOOD; |
942 | | |
943 | | /* Verify the chunk signature */ |
944 | 2.51k | UA_LOG_TRACE_CHANNEL(sp->logger, channel, "Verifying chunk signature"); |
945 | 2.51k | size_t sigsize = signatureAlgorithm->getRemoteSignatureSize(sp, cc); |
946 | 2.51k | UA_CHECK(sigsize < chunk->length, return UA_STATUSCODE_BADSECURITYCHECKSFAILED); |
947 | 2.51k | const UA_ByteString content = {chunk->length - sigsize, chunk->data}; |
948 | 2.51k | const UA_ByteString sig = {sigsize, chunk->data + chunk->length - sigsize}; |
949 | | |
950 | | /* OPC UA Part 6 v1.05.07 §6.7.5 "ChannelThumbprint" (only for the first |
951 | | * OPN exchange and only for SecurityPolicies with |
952 | | * secureChannelEnhancements = true). For the *first* OPN only: |
953 | | * |
954 | | * Server side (verify an incoming OPN request): the request |
955 | | * signature is unknown to the server until it has been |
956 | | * verified. Capture the bytes now (BEFORE stripping) so the |
957 | | * sign path of the OPN response can append them. |
958 | | * |
959 | | * Client side (verify the OPN response): the client's own |
960 | | * request signature was stored in firstRequestSignature when |
961 | | * the request was sent. Extend the verify content with it. |
962 | | * |
963 | | * For OPN *renewals* the firstRequestSignature is empty (it was |
964 | | * cleared by the first exchange) and the normal v1.05.06 verify |
965 | | * path is used. */ |
966 | 2.51k | UA_ByteString verifyContent = content; |
967 | 2.51k | UA_Byte *extendedBuf = NULL; |
968 | 2.51k | UA_Boolean capturedIncoming = false; |
969 | | /* First-OPN only (channelThumbprint empty). On renewals neither capture nor |
970 | | * extend - the v1.05.06 verify path is used. */ |
971 | 2.51k | UA_Boolean firstOPN = (channel->enhancedSecurity && |
972 | 0 | messageType == UA_MESSAGETYPE_OPN && |
973 | 0 | channel->channelThumbprint.length == 0); |
974 | 2.51k | if(firstOPN) { |
975 | 0 | if(channel->firstRequestSignature.length == 0) { |
976 | | /* First-OPN, receiving side: capture the incoming signature. |
977 | | * The sign path of the response will consume it. */ |
978 | 0 | UA_StatusCode clip = UA_ByteString_copy(&sig, &channel->firstRequestSignature); |
979 | 0 | UA_CHECK_STATUS(clip, return clip); |
980 | 0 | capturedIncoming = true; |
981 | 0 | } else { |
982 | | /* Verifying the OPN response: extend the content. */ |
983 | 0 | extendedBuf = (UA_Byte*)UA_malloc( |
984 | 0 | content.length + channel->firstRequestSignature.length); |
985 | 0 | if(!extendedBuf) { |
986 | 0 | UA_ByteString_clear(&channel->firstRequestSignature); |
987 | 0 | return UA_STATUSCODE_BADOUTOFMEMORY; |
988 | 0 | } |
989 | 0 | memcpy(extendedBuf, content.data, content.length); |
990 | 0 | memcpy(extendedBuf + content.length, |
991 | 0 | channel->firstRequestSignature.data, |
992 | 0 | channel->firstRequestSignature.length); |
993 | 0 | verifyContent.data = extendedBuf; |
994 | 0 | verifyContent.length = |
995 | 0 | content.length + channel->firstRequestSignature.length; |
996 | 0 | } |
997 | 0 | } |
998 | | |
999 | 2.51k | res = signatureAlgorithm->verify(sp, cc, &verifyContent, &sig); |
1000 | 2.51k | UA_free(extendedBuf); |
1001 | | |
1002 | | /* Single-use: if we just consumed the stored signature (client side |
1003 | | * verifying the response), clear it. If we just captured the |
1004 | | * incoming signature (server side verifying the request), keep |
1005 | | * it — the sign path of the response will use and then clear it. */ |
1006 | 2.51k | if(firstOPN && !capturedIncoming) { |
1007 | 0 | UA_ByteString_clear(&channel->firstRequestSignature); |
1008 | 0 | } |
1009 | | |
1010 | 2.51k | UA_CHECK_STATUS(res, UA_LOG_WARNING_CHANNEL(sp->logger, channel, |
1011 | 2.51k | "Could not verify the signature"); |
1012 | 2.51k | return res); |
1013 | | |
1014 | | /* OPC UA Part 6 v1.05.07 ChannelThumbprint: on the client, the |
1015 | | * verified first-OPN *response* signature (sig) is the |
1016 | | * ChannelThumbprint. capturedIncoming is false only on the |
1017 | | * client response-verify path. Capture once, preserve across |
1018 | | * renewals; binds the session SignatureData to this channel. */ |
1019 | 2.51k | if(channel->enhancedSecurity && messageType == UA_MESSAGETYPE_OPN && |
1020 | 0 | !capturedIncoming && channel->channelThumbprint.length == 0) { |
1021 | 0 | UA_StatusCode tp = UA_ByteString_copy(&sig, &channel->channelThumbprint); |
1022 | 0 | UA_CHECK_STATUS(tp, return tp); |
1023 | 0 | } |
1024 | | |
1025 | | /* Compute the padding if the payload is encrypted (not ECC policy) */ |
1026 | 2.51k | size_t padSize = 0; |
1027 | 2.51k | if((messageType != UA_MESSAGETYPE_OPN && |
1028 | 0 | channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) || |
1029 | 2.51k | (messageType == UA_MESSAGETYPE_OPN && |
1030 | 2.51k | sp->policyType == UA_SECURITYPOLICYTYPE_RSA)) { |
1031 | 0 | padSize = decodePadding(channel, encryptionAlgorithm, chunk, sigsize); |
1032 | 0 | UA_LOG_TRACE_CHANNEL(sp->logger, channel, "Calculated padding size to be %lu", |
1033 | 0 | (long unsigned)padSize); |
1034 | 0 | } |
1035 | | |
1036 | | /* Verify the content length. The encrypted payload has to be at least 9 |
1037 | | * bytes long: 8 byte for the SequenceHeader and one byte for the actual |
1038 | | * message */ |
1039 | 2.51k | UA_CHECK(offset + padSize + sigsize + 9 < chunk->length, |
1040 | 2.51k | UA_LOG_ERROR_CHANNEL(sp->logger, channel, "Impossible padding value"); |
1041 | 2.51k | return UA_STATUSCODE_BADSECURITYCHECKSFAILED); |
1042 | | |
1043 | | /* Hide the signature and padding */ |
1044 | 2.49k | chunk->length -= (sigsize + padSize); |
1045 | 2.49k | return UA_STATUSCODE_GOOD; |
1046 | 2.51k | } |
1047 | | |
1048 | | /* The certificate in the header is verified via the configured PKI plugin as |
1049 | | * certificateVerification.verifyCertificate(...). We cannot do it here because |
1050 | | * the client/server context is needed. */ |
1051 | | UA_StatusCode |
1052 | | checkAsymHeader(UA_SecureChannel *channel, |
1053 | 4.99k | const UA_AsymmetricAlgorithmSecurityHeader *asymHeader) { |
1054 | 4.99k | const UA_SecurityPolicy *sp = channel->securityPolicy; |
1055 | 4.99k | if(!UA_String_equal(&sp->policyUri, &asymHeader->securityPolicyUri)) |
1056 | 0 | return UA_STATUSCODE_BADSECURITYPOLICYREJECTED; |
1057 | 4.99k | return sp->compareCertThumbprint(sp, &asymHeader->receiverCertificateThumbprint); |
1058 | 4.99k | } |
1059 | | |
1060 | | UA_StatusCode |
1061 | | checkSymHeader(UA_SecureChannel *channel, const UA_UInt32 tokenId, |
1062 | 7.59k | UA_DateTime nowMonotonic) { |
1063 | 7.59k | UA_SecurityPolicy *sp = channel->securityPolicy; |
1064 | 7.59k | (void)sp; |
1065 | | |
1066 | | /* If no match, try to revolve to the next token after a |
1067 | | * RenewSecureChannel */ |
1068 | 7.59k | UA_StatusCode retval = UA_STATUSCODE_GOOD; |
1069 | 7.59k | UA_ChannelSecurityToken *token = &channel->securityToken; |
1070 | 7.59k | switch(channel->renewState) { |
1071 | 7.59k | case UA_SECURECHANNELRENEWSTATE_NORMAL: |
1072 | 7.59k | case UA_SECURECHANNELRENEWSTATE_SENT: |
1073 | 7.59k | default: |
1074 | 7.59k | if(tokenId != channel->securityToken.tokenId) |
1075 | 0 | return UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN; |
1076 | 7.59k | break; |
1077 | | |
1078 | 7.59k | case UA_SECURECHANNELRENEWSTATE_NEWTOKEN_SERVER: |
1079 | | /* Old token still in use. After an ISSUE there is no old token, only a |
1080 | | * placeholder with TokenId zero and no keys (Part 4, 5.6.2). It was |
1081 | | * never issued, so it is unknown (Part 6, 6.7.2.3). */ |
1082 | 0 | if(tokenId == channel->securityToken.tokenId && tokenId != 0) |
1083 | 0 | break; |
1084 | | |
1085 | | /* Not the new token */ |
1086 | 0 | UA_CHECK(tokenId == channel->altSecurityToken.tokenId, |
1087 | 0 | UA_LOG_ERROR_CHANNEL(sp->logger, channel, "Unknown SecurityToken"); |
1088 | 0 | return UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN); |
1089 | | |
1090 | | /* Roll over to the new token, generate new local and remote keys */ |
1091 | 0 | channel->renewState = UA_SECURECHANNELRENEWSTATE_NORMAL; |
1092 | 0 | channel->securityToken = channel->altSecurityToken; |
1093 | 0 | UA_ChannelSecurityToken_init(&channel->altSecurityToken); |
1094 | 0 | retval |= UA_SecureChannel_generateLocalKeys(channel); |
1095 | 0 | retval |= generateRemoteKeys(channel); |
1096 | 0 | UA_CHECK_STATUS(retval, return retval); |
1097 | 0 | break; |
1098 | | |
1099 | 0 | case UA_SECURECHANNELRENEWSTATE_NEWTOKEN_CLIENT: |
1100 | | /* The server is still using the old token. That's okay. After an |
1101 | | * ISSUE the old token is the placeholder with TokenId zero, which the |
1102 | | * server never issued (Part 4, 5.6.2). */ |
1103 | 0 | if(tokenId == channel->altSecurityToken.tokenId && tokenId != 0) { |
1104 | 0 | token = &channel->altSecurityToken; |
1105 | 0 | break; |
1106 | 0 | } |
1107 | | |
1108 | | /* Not the new token */ |
1109 | 0 | UA_CHECK(tokenId == channel->securityToken.tokenId, |
1110 | 0 | UA_LOG_ERROR_CHANNEL(sp->logger, channel, "Unknown SecurityToken"); |
1111 | 0 | return UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN); |
1112 | | |
1113 | | /* The remote server uses the new token for the first time. Delete the |
1114 | | * old token and roll the remote key over. The local key already uses |
1115 | | * the nonce pair from the last OPN exchange. */ |
1116 | 0 | channel->renewState = UA_SECURECHANNELRENEWSTATE_NORMAL; |
1117 | 0 | UA_ChannelSecurityToken_init(&channel->altSecurityToken); |
1118 | 0 | retval = generateRemoteKeys(channel); |
1119 | 0 | UA_CHECK_STATUS(retval, return retval); |
1120 | 7.59k | } |
1121 | | |
1122 | 7.59k | UA_DateTime timeout = token->createdAt + (token->revisedLifetime * UA_DATETIME_MSEC); |
1123 | 7.59k | if(channel->state == UA_SECURECHANNELSTATE_OPEN && timeout < nowMonotonic) { |
1124 | 0 | UA_LOG_ERROR_CHANNEL(sp->logger, channel, "SecurityToken timed out"); |
1125 | 0 | UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_TIMEOUT); |
1126 | 0 | return UA_STATUSCODE_BADSECURECHANNELCLOSED; |
1127 | 0 | } |
1128 | | |
1129 | 7.59k | return UA_STATUSCODE_GOOD; |
1130 | 7.59k | } |
1131 | | |
1132 | | UA_Boolean |
1133 | 0 | UA_SecureChannel_checkTimeout(UA_SecureChannel *channel, UA_DateTime nowMonotonic) { |
1134 | | /* Compute the timeout date of the SecurityToken */ |
1135 | 0 | UA_DateTime timeout = channel->securityToken.createdAt + |
1136 | 0 | (UA_DateTime)(channel->securityToken.revisedLifetime * UA_DATETIME_MSEC); |
1137 | | |
1138 | | /* The token has timed out. Try to do the token revolving now instead of |
1139 | | * shutting the channel down. |
1140 | | * |
1141 | | * Part 4, 5.5.2 says: Servers shall use the existing SecurityToken to |
1142 | | * secure outgoing Messages until the SecurityToken expires or the |
1143 | | * Server receives a Message secured with a new SecurityToken.*/ |
1144 | 0 | if(timeout < nowMonotonic && |
1145 | 0 | channel->renewState == UA_SECURECHANNELRENEWSTATE_NEWTOKEN_SERVER) { |
1146 | | /* Revolve the token manually. This is otherwise done in checkSymHeader. */ |
1147 | 0 | channel->renewState = UA_SECURECHANNELRENEWSTATE_NORMAL; |
1148 | 0 | channel->securityToken = channel->altSecurityToken; |
1149 | 0 | UA_ChannelSecurityToken_init(&channel->altSecurityToken); |
1150 | 0 | UA_SecureChannel_generateLocalKeys(channel); |
1151 | 0 | generateRemoteKeys(channel); |
1152 | | |
1153 | | /* Use the timeout of the new SecurityToken */ |
1154 | 0 | timeout = channel->securityToken.createdAt + |
1155 | 0 | (UA_DateTime)(channel->securityToken.revisedLifetime * UA_DATETIME_MSEC); |
1156 | 0 | } |
1157 | |
|
1158 | 0 | return (timeout < nowMonotonic); |
1159 | 0 | } |