Coverage Report

Created: 2026-06-09 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541/src/util/ua_encryptedsecret.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 2025 (c) Siemens AG (Author: Tin Raic)
6
 *    Copyright 2025-2026 (c) o6 Automation GmbH (Author: Julius Pfrommer)
7
 */
8
9
#include "ua_util_internal.h"
10
11
/************************/
12
/* ECC Encrypted Secret */
13
/************************/
14
15
typedef struct {
16
    /* Common Header */
17
    UA_NodeId typeId;
18
    UA_Byte encodingMask;
19
    UA_UInt32 length;
20
    UA_String securityPolicyUri;
21
    UA_ByteString certificate;
22
    UA_DateTime signingTime;
23
    UA_UInt16 keyDataLen;
24
25
    /* Policy Header*/
26
    UA_ByteString senderPublicKey;
27
    UA_ByteString receiverPublicKey;
28
29
    /* Payload */
30
    UA_ByteString nonce;
31
    UA_ByteString secret;
32
    /* UA_ByteString padding; // Computed when needed */
33
34
    /* Signature */
35
    UA_Byte* signature;
36
} UA_EccEncryptedSecretStruct;
37
38
static void
39
0
UA_EccEncryptedSecretStruct_init(UA_EccEncryptedSecretStruct* es) {
40
0
    memset(es, 0, sizeof(UA_EccEncryptedSecretStruct));
41
0
}
42
43
static void
44
0
UA_EccEncryptedSecretStruct_clear(UA_EccEncryptedSecretStruct* es) {
45
0
    UA_String_clear(&es->securityPolicyUri);
46
0
    UA_ByteString_clear(&es->certificate);
47
0
    UA_ByteString_clear(&es->senderPublicKey);
48
0
    UA_ByteString_clear(&es->receiverPublicKey);
49
0
    UA_ByteString_clear(&es->nonce);
50
0
    UA_ByteString_clear(&es->secret);
51
0
    UA_EccEncryptedSecretStruct_init(es);
52
0
}
53
54
static size_t
55
0
UA_EccEncryptedSecret_getCommonHeaderSize(const UA_EccEncryptedSecretStruct* src) {
56
0
    size_t len = 0;
57
0
    len += UA_calcSizeBinary(&src->typeId, &UA_TYPES[UA_TYPES_NODEID], NULL);
58
0
    len += UA_calcSizeBinary(&src->encodingMask, &UA_TYPES[UA_TYPES_BYTE], NULL);
59
0
    len += UA_calcSizeBinary(&src->length, &UA_TYPES[UA_TYPES_UINT32], NULL);
60
0
    len += UA_calcSizeBinary(&src->securityPolicyUri, &UA_TYPES[UA_TYPES_STRING], NULL);
61
0
    len += UA_calcSizeBinary(&src->certificate, &UA_TYPES[UA_TYPES_BYTESTRING], NULL);
62
0
    len += UA_calcSizeBinary(&src->signingTime, &UA_TYPES[UA_TYPES_DATETIME], NULL);
63
0
    len += UA_calcSizeBinary(&src->keyDataLen, &UA_TYPES[UA_TYPES_UINT16], NULL);
64
0
    return len;
65
0
}
66
67
static size_t
68
0
UA_EccEncryptedSecret_getPolicyHeaderSize(const UA_EccEncryptedSecretStruct* src) {
69
0
    size_t len = 0;
70
0
    len += UA_calcSizeBinary(&src->senderPublicKey, &UA_TYPES[UA_TYPES_BYTESTRING], NULL);
71
0
    len += UA_calcSizeBinary(&src->receiverPublicKey, &UA_TYPES[UA_TYPES_BYTESTRING], NULL);
72
0
    return len;
73
0
}
74
75
static UA_StatusCode
76
UA_EccEncryptedSecret_serializeCommonHeader(const UA_EccEncryptedSecretStruct *src,
77
0
                                            UA_Byte** bufPos, const UA_Byte* bufEnd) {
78
0
    UA_UInt32 length32 = (UA_UInt32)src->length;
79
0
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
80
0
    ret |= UA_NodeId_encodeBinary(&src->typeId, bufPos, bufEnd);
81
0
    ret |= UA_Byte_encodeBinary(&src->encodingMask, bufPos, bufEnd);
82
0
    ret |= UA_UInt32_encodeBinary(&length32, bufPos, bufEnd);
83
0
    ret |= UA_String_encodeBinary(&src->securityPolicyUri, bufPos, bufEnd);
84
0
    ret |= UA_ByteString_encodeBinary(&src->certificate, bufPos, bufEnd);
85
0
    ret |= UA_DateTime_encodeBinary(&src->signingTime, bufPos, bufEnd);
86
0
    ret |= UA_UInt16_encodeBinary(&src->keyDataLen, bufPos, bufEnd);
87
0
    return ret;
88
0
}
89
90
static UA_StatusCode
91
UA_EccEncryptedSecret_serializePolicyHeader(const UA_EccEncryptedSecretStruct *src,
92
0
                                            UA_Byte** bufPos, const UA_Byte* bufEnd) {
93
0
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
94
0
    ret |= UA_ByteString_encodeBinary(&src->senderPublicKey, bufPos, bufEnd);
95
0
    ret |= UA_ByteString_encodeBinary(&src->receiverPublicKey, bufPos, bufEnd);
96
0
    return ret;
97
0
}
98
99
static UA_StatusCode
100
UA_EccEncryptedSecret_deserializeCommonHeader(UA_EccEncryptedSecret *src,
101
                                              UA_EccEncryptedSecretStruct *dest,
102
0
                                              size_t* offset) {
103
0
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
104
0
    ret |= UA_NodeId_decodeBinary(src, offset, &dest->typeId);
105
0
    ret |= UA_Byte_decodeBinary(src, offset, &dest->encodingMask);
106
0
    ret |= UA_UInt32_decodeBinary(src, offset, &dest->length);
107
0
    ret |= UA_String_decodeBinary(src, offset, &dest->securityPolicyUri);
108
0
    ret |= UA_ByteString_decodeBinary(src, offset, &dest->certificate);
109
0
    ret |= UA_DateTime_decodeBinary(src, offset, &dest->signingTime);
110
0
    ret |= UA_UInt16_decodeBinary(src, offset, &dest->keyDataLen);
111
0
    return ret;
112
0
}
113
114
static UA_StatusCode
115
UA_EccEncryptedSecret_deserializePolicyHeader(UA_EccEncryptedSecret *src,
116
                                              UA_EccEncryptedSecretStruct *dest,
117
0
                                              size_t* offset) {
118
0
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
119
0
    ret |= UA_ByteString_decodeBinary(src, offset, &dest->senderPublicKey);
120
0
    ret |= UA_ByteString_decodeBinary(src, offset, &dest->receiverPublicKey);
121
0
    return ret;
122
0
}
123
124
UA_StatusCode
125
encryptUserIdentityTokenEcc(UA_Logger *logger, UA_SecureChannel *channel,
126
                            const UA_SecurityPolicy *sp, void *spContext,
127
                            UA_ByteString *tokenData,
128
                            const UA_ByteString serverSessionNonce,
129
0
                            const UA_ByteString serverEphemeralPubKey) {
130
    /* Extract some basic information from the SecurityPolicy */
131
0
    size_t symKeyLen = sp->symEncryptionAlgorithm.getLocalKeyLength(sp, spContext);
132
0
    size_t ivLen = sp->symEncryptionAlgorithm.getRemoteBlockSize(sp, spContext);
133
0
    size_t sigLen = sp->asymSignatureAlgorithm.getRemoteSignatureSize(sp, spContext);
134
0
    UA_assert(symKeyLen > 0 && ivLen > 0);
135
136
    /* Filling out the EccEncryptedSecretStruct fields. The length field is
137
     * computed after. */
138
0
    UA_EccEncryptedSecretStruct secret;
139
0
    UA_EccEncryptedSecretStruct_init(&secret);
140
0
    secret.typeId = UA_NS0ID(ECCENCRYPTEDSECRET);
141
0
    secret.encodingMask = 0x01;
142
0
    secret.signingTime = UA_DateTime_now();
143
144
    /* Copy-only methods */
145
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
146
0
    retval |= UA_String_copy(&sp->policyUri, &secret.securityPolicyUri);
147
0
    retval |= UA_ByteString_copy(&sp->localCertificate, &secret.certificate);
148
0
    retval |= UA_ByteString_copy(&serverEphemeralPubKey, &secret.receiverPublicKey);
149
0
    retval |= UA_ByteString_copy(&serverSessionNonce, &secret.nonce);
150
0
    retval |= UA_ByteString_copy(tokenData, &secret.secret);
151
0
    if(retval != UA_STATUSCODE_GOOD) {
152
0
        UA_EccEncryptedSecretStruct_clear(&secret);
153
0
        return retval;
154
0
    }
155
156
    /* Generate a new local ephemeral key. The private part remains persisted
157
     * inside the SecurityPolicy. */
158
0
    size_t ephKeyLen = sp->nonceLength; /* Also length of the ephemeral public key */
159
0
    retval = UA_ByteString_allocBuffer(&secret.senderPublicKey, ephKeyLen);
160
0
    if(retval != UA_STATUSCODE_GOOD) {
161
0
        UA_EccEncryptedSecretStruct_clear(&secret);
162
0
        return retval;
163
0
    }
164
0
    secret.senderPublicKey.data[0] = 'e';
165
0
    secret.senderPublicKey.data[1] = 'p';
166
0
    secret.senderPublicKey.data[2] = 'h';
167
0
    retval = sp->generateNonce(sp, spContext, &secret.senderPublicKey);
168
0
    if(retval != UA_STATUSCODE_GOOD) {
169
0
        UA_LOG_ERROR_CHANNEL(logger, channel,
170
0
                     "EccEncryptedSecret: Failed to generate local ephemeral key");
171
0
        UA_EccEncryptedSecretStruct_clear(&secret);
172
0
        return retval;
173
0
    }
174
175
    /* Length of the encrypted content. If the InitializationVectorLength is
176
     * less than 16 bytes, then 16 bytes are used instead. */
177
0
    size_t encryptedLength =
178
0
        UA_ByteString_calcSizeBinary(&secret.nonce) +
179
0
        UA_ByteString_calcSizeBinary(&secret.secret) + 2; /* Incl padding length */
180
0
    size_t paddingIvLen = ivLen;
181
0
    if(paddingIvLen < 16)
182
0
        paddingIvLen = 16;
183
0
    size_t paddingLen = paddingIvLen - (encryptedLength % paddingIvLen);
184
0
    encryptedLength += paddingLen;
185
186
    /* Compute the total length including the headers and the signature */
187
0
    size_t signatureLen = sp->asymSignatureAlgorithm.
188
0
        getLocalSignatureSize(sp, spContext);
189
0
    secret.keyDataLen = (UA_UInt16)
190
0
        UA_EccEncryptedSecret_getPolicyHeaderSize(&secret);
191
0
    size_t totalLength = encryptedLength + secret.keyDataLen +
192
0
        UA_EccEncryptedSecret_getCommonHeaderSize(&secret) + signatureLen;
193
0
    secret.length = (UA_UInt32)totalLength;
194
195
    /* Compute the symmetric key to encrypt */
196
0
    UA_ByteString symEncKeyMaterial;
197
0
    retval = UA_ByteString_allocBuffer(&symEncKeyMaterial, symKeyLen+ivLen);
198
0
    if(retval != UA_STATUSCODE_GOOD) {
199
0
        UA_EccEncryptedSecretStruct_clear(&secret);
200
0
        return retval;
201
0
    }
202
203
    /* This is a (temporary) measure so that the salt generation function (for
204
     * the symmetric key derivation ) knows that the salt is generated for
205
     * session authentication (to choose the correct label) */
206
    /* TODO: find a better way to signal symmetric key generation for session
207
     * authentication */
208
0
    symEncKeyMaterial.data[0] = 0x03;
209
0
    symEncKeyMaterial.data[1] = 0x03;
210
0
    symEncKeyMaterial.data[2] = 0x04;
211
0
    retval = sp->generateKey(sp, spContext, &secret.receiverPublicKey,
212
0
                             &secret.senderPublicKey, &symEncKeyMaterial);
213
0
    if(retval != UA_STATUSCODE_GOOD) {
214
0
        UA_LOG_ERROR_CHANNEL(logger, channel,
215
0
                             "EccEncryptedSecret: Failed to derive key material");
216
0
        UA_ByteString_clear(&symEncKeyMaterial);
217
0
        UA_EccEncryptedSecretStruct_clear(&secret);
218
0
        return retval;
219
0
    }
220
221
    /* Extracting the key and the initialization vector from the key material */
222
0
    UA_ByteString encKey = {symKeyLen, symEncKeyMaterial.data};
223
0
    UA_ByteString iv = {ivLen, &symEncKeyMaterial.data[symKeyLen]};
224
0
    retval |= sp->setLocalSymEncryptingKey(sp, spContext, &encKey);
225
0
    retval |= sp->setLocalSymIv(sp, spContext, &iv);
226
0
    UA_ByteString_clear(&symEncKeyMaterial);
227
0
    if(retval != UA_STATUSCODE_GOOD) {
228
0
        UA_LOG_ERROR_CHANNEL(logger, channel,
229
0
                             "EccEncryptedSecret: Failed to set EncryptingKey/"
230
0
                             "IV in the SecurityPolicy");
231
0
        UA_EccEncryptedSecretStruct_clear(&secret);
232
0
        return retval;
233
0
    }
234
235
    /* Allocate the output buffer */
236
0
    UA_ByteString output;
237
0
    retval = UA_ByteString_allocBuffer(&output, totalLength);
238
0
    if(retval != UA_STATUSCODE_GOOD) {
239
0
        UA_EccEncryptedSecretStruct_clear(&secret);
240
0
        return retval;
241
0
    }
242
243
    /* Encode all the content into the output buffer */
244
0
    UA_Byte* bufPos = output.data;
245
0
    UA_Byte* bufEnd = output.data + output.length;
246
0
    retval |= UA_EccEncryptedSecret_serializeCommonHeader(&secret, &bufPos, bufEnd);
247
0
    retval |= UA_EccEncryptedSecret_serializePolicyHeader(&secret, &bufPos, bufEnd);
248
0
    UA_Byte* payloadPos = bufPos;
249
0
    retval |= UA_ByteString_encodeBinary(&secret.nonce, &bufPos, bufEnd);
250
0
    retval |= UA_ByteString_encodeBinary(&secret.secret, &bufPos, bufEnd);
251
0
    UA_Byte pad = paddingLen & 0xFF;
252
0
    for(size_t i = 0; i < paddingLen; i++) {
253
0
        *bufPos = pad;
254
0
        bufPos++;
255
0
    }
256
0
    UA_UInt16 paddingLen16 = (UA_UInt16)paddingLen;
257
0
    retval |= UA_UInt16_encodeBinary(&paddingLen16, &bufPos, bufEnd);
258
0
    if(retval != UA_STATUSCODE_GOOD) {
259
0
        UA_EccEncryptedSecretStruct_clear(&secret);
260
0
        UA_ByteString_clear(&output);
261
0
        return retval;
262
0
    }
263
264
    /* Encrypt the payload part in-situ */
265
0
    UA_ByteString payload = {(size_t)(bufPos - payloadPos), payloadPos};
266
0
    retval |= sp->symEncryptionAlgorithm.encrypt(sp, spContext, &payload);
267
0
    if(retval != UA_STATUSCODE_GOOD) {
268
0
        UA_LOG_ERROR_CHANNEL(logger, channel,
269
0
                     "EccEncryptedSecret: Failed to encrypt the payload");
270
0
        UA_EccEncryptedSecretStruct_clear(&secret);
271
0
        UA_ByteString_clear(&output);
272
0
        return retval;
273
0
    }
274
275
0
    UA_assert(bufPos + sigLen == bufEnd);
276
277
    /* Compute the overall signature */
278
0
    UA_ByteString sigContent = {(size_t)(bufPos - output.data), output.data};
279
0
    UA_ByteString signature = {sigLen, bufPos};
280
0
    retval = sp->asymSignatureAlgorithm.sign(sp, spContext, &sigContent, &signature);
281
0
    if(retval != UA_STATUSCODE_GOOD) {
282
0
        UA_LOG_ERROR_CHANNEL(logger, channel,
283
0
                     "EccEncryptedSecret: Failed to sign the EccEncryptedSecret");
284
0
        UA_EccEncryptedSecretStruct_clear(&secret);
285
0
        UA_ByteString_clear(&output);
286
0
        return retval;
287
0
    }
288
289
    /* Replace tokenData with the output */
290
0
    UA_ByteString_clear(tokenData);
291
0
    *tokenData = output;
292
293
0
    UA_EccEncryptedSecretStruct_clear(&secret);
294
0
    return UA_STATUSCODE_GOOD;
295
0
}
296
297
UA_StatusCode
298
decryptUserTokenEcc(UA_Logger *logger, UA_SecureChannel *channel,
299
                    const UA_SecurityPolicy *sp, void *spContext,
300
                    UA_ByteString sessionServerNonce,
301
0
                    UA_EccEncryptedSecret *es) {
302
    /* ECC usage verified before calling into this function */
303
0
    UA_assert(sp->policyType == UA_SECURITYPOLICYTYPE_ECC);
304
305
    /* Define and initialize in case of clean-up */
306
0
    UA_StatusCode res = UA_STATUSCODE_GOOD;
307
0
    UA_EccEncryptedSecretStruct esd;
308
0
    UA_EccEncryptedSecretStruct_init(&esd);
309
0
    UA_ByteString symEncKeyMaterial = UA_BYTESTRING_NULL;
310
0
    UA_ByteString pass = UA_BYTESTRING_NULL;
311
312
0
    size_t offset = 0;
313
0
    res = UA_EccEncryptedSecret_deserializeCommonHeader(es, &esd, &offset);
314
0
    if(res != UA_STATUSCODE_GOOD) {
315
0
        UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
316
0
                             "Failed to decode the common header");
317
0
        goto cleanecc;
318
0
    }
319
320
    /* Check TypeId */
321
0
    UA_NodeId eccTypeId = UA_NS0ID(ECCENCRYPTEDSECRET);
322
0
    if(!UA_NodeId_equal(&eccTypeId, &esd.typeId) ||
323
0
       esd.encodingMask != 0x01 ||
324
0
       !UA_String_equal(&esd.securityPolicyUri, &sp->policyUri)) {
325
0
        UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
326
0
                             "Inconsistent common header");
327
0
        res = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
328
0
        goto cleanecc;
329
0
    }
330
331
    /* Verify signature */
332
0
    size_t sigLen = sp->asymSignatureAlgorithm.getRemoteSignatureSize(sp, spContext);
333
0
    size_t signedDataLen = es->length - sigLen;
334
0
    UA_ByteString signedData = {signedDataLen, es->data};
335
0
    UA_ByteString signature = {sigLen, &es->data[signedDataLen]};
336
0
    res = sp->asymSignatureAlgorithm.verify(sp, spContext, &signedData, &signature);
337
0
    if(res != UA_STATUSCODE_GOOD) {
338
0
        UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
339
0
                             "Signature verification failed");
340
0
        goto cleanecc;
341
0
    }
342
343
0
    size_t oldoffset = offset;
344
0
    res = UA_EccEncryptedSecret_deserializePolicyHeader(es, &esd, &offset);
345
0
    if(res != UA_STATUSCODE_GOOD) {
346
0
        UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
347
0
                             "Failed to decode the policy header");
348
0
        goto cleanecc;
349
0
    }
350
351
    /* Sanity check of the key data length.
352
     * This needs to include the 2x4 byte length fields. */
353
0
    if(esd.keyDataLen != (UA_UInt16)(offset - oldoffset)) {
354
0
        UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
355
0
                             "Inconstent KeyDataLength");
356
0
        res = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
357
0
        goto cleanecc;
358
0
    }
359
360
    /* Check the payload length */
361
0
    if(es->length <= offset + sigLen) {
362
0
        UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
363
0
                             "Inconstent payload / signature length");
364
0
        res = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
365
0
        goto cleanecc;
366
0
    }
367
0
    UA_ByteString payload = {es->length - offset - sigLen, es->data + offset};
368
369
    /* Deriving (remote) symmetric encryption key to decrypt the payload */
370
0
    size_t symKeyLen = sp->symEncryptionAlgorithm.getRemoteKeyLength(sp, spContext);
371
0
    size_t ivLen = sp->symEncryptionAlgorithm.getRemoteBlockSize(sp, spContext);
372
0
    res = UA_ByteString_allocBuffer(&symEncKeyMaterial, symKeyLen+ivLen);
373
0
    if(res != UA_STATUSCODE_GOOD)
374
0
        goto cleanecc;
375
376
    /* This is a (temporary) measure so that the salt generation function (for
377
     * the symmetric key derivation ) knows that the salt is generated for
378
     * session authentication (to choose the correct label) */
379
    /* TODO: find a better way to signal symmetric key generation for session
380
     * authentication */
381
0
    symEncKeyMaterial.data[0] = 0x03;
382
0
    symEncKeyMaterial.data[1] = 0x03;
383
0
    symEncKeyMaterial.data[2] = 0x04;
384
385
    /* Call logic for server for session authentication: receiver public key is
386
     * local (server), sender public key is remote (client) */
387
0
    res = sp->generateKey(sp, spContext, &esd.receiverPublicKey,
388
0
                          &esd.senderPublicKey, &symEncKeyMaterial);
389
0
    if(res != UA_STATUSCODE_GOOD) {
390
0
        UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
391
0
                             "Failed to derive key material");
392
0
        goto cleanecc;
393
0
    }
394
395
    /* Extract the encryption key and the initialization vector */
396
0
    UA_ByteString encKey = {symKeyLen, symEncKeyMaterial.data};
397
0
    UA_ByteString iv = {ivLen, &symEncKeyMaterial.data[symKeyLen]};
398
399
    /* Set IV and RemoteEncryptingKey. That is all we need to decode the
400
     * secret. */
401
0
    res |= sp->setRemoteSymEncryptingKey(sp, spContext, &encKey);
402
0
    res |= sp->setRemoteSymIv(sp, spContext, &iv);
403
0
    if(res != UA_STATUSCODE_GOOD) {
404
0
        UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
405
0
                             "Failed to set IV/RemoteSymEncryptingKey");
406
0
        goto cleanecc;
407
0
    }
408
409
    /* Decrypt payload (password) */
410
0
    res = sp->symEncryptionAlgorithm.decrypt(sp, spContext, &payload);
411
0
    if(res != UA_STATUSCODE_GOOD) {
412
0
        UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
413
0
                             "Failed to decrypt the payload");
414
0
        goto cleanecc;
415
0
    }
416
417
    /* Decode nonce and secret */
418
0
    offset = 0; /* Within the payload */
419
0
    UA_ByteString nonce;
420
0
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
421
0
    ret |= UA_ByteString_decodeBinary(&payload, &offset, &nonce);
422
0
    ret |= UA_ByteString_decodeBinary(&payload, &offset, &pass);
423
0
    if(ret != UA_STATUSCODE_GOOD) {
424
0
        UA_ByteString_clear(&nonce);
425
0
        UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
426
0
                             "Failed to decode the payload");
427
0
        goto cleanecc;
428
0
    }
429
430
    /* Compare the nonce */
431
0
    UA_Boolean nonceMatch = UA_ByteString_equal(&sessionServerNonce, &nonce);
432
0
    UA_ByteString_clear(&nonce);
433
0
    if(!nonceMatch) {
434
0
        UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
435
0
                             "Nonce does not match");
436
0
        res = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
437
0
        goto cleanecc;
438
0
    }
439
440
    /* Decode the padding length and validate */
441
0
    UA_UInt16 paddingSize = 0;
442
0
    size_t paddingOffset = payload.length - 2;
443
0
    UA_UInt16_decodeBinary(&payload, &paddingOffset, &paddingSize);
444
0
    UA_Byte padd = (UA_Byte)paddingSize;
445
0
    for(; offset < payload.length-2; offset++) {
446
0
        if(payload.data[offset] != padd) {
447
0
            UA_LOG_ERROR_CHANNEL(logger, channel,
448
0
                                 "EccEncryptedSecret: Inconsistent padding");
449
0
            res = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
450
0
            goto cleanecc;
451
0
        }
452
0
    }
453
454
    /* Copy the password to the output */
455
0
    memcpy(es->data, pass.data, pass.length);
456
0
    es->length = pass.length;
457
458
0
cleanecc:
459
0
    UA_EccEncryptedSecretStruct_clear(&esd);
460
0
    UA_ByteString_clear(&symEncKeyMaterial);
461
0
    UA_ByteString_clear(&pass);
462
0
    return res;
463
0
}
464
465
/***************************/
466
/* Legacy Encrypted Secret */
467
/***************************/
468
469
UA_StatusCode
470
encryptSecretLegacy(const UA_SecurityPolicy *sp, void *spContext,
471
                    const UA_ByteString serverSessionNonce,
472
0
                    UA_ByteString *tokenData) {
473
    /* Compute the encrypted length (at least one byte padding) */
474
0
    size_t plainTextBlockSize = sp->asymEncryptionAlgorithm.
475
0
        getRemotePlainTextBlockSize(sp, spContext);
476
0
    size_t encryptedBlockSize = sp->asymEncryptionAlgorithm.
477
0
        getRemoteBlockSize(sp, spContext);
478
0
    UA_UInt32 length =
479
0
        (UA_UInt32)(tokenData->length + serverSessionNonce.length);
480
0
    UA_UInt32 totalLength = length + 4; /* Including the length field */
481
0
    size_t blocks = totalLength / plainTextBlockSize;
482
0
    if(totalLength % plainTextBlockSize != 0)
483
0
        blocks++;
484
0
    size_t encryptedLength = blocks * encryptedBlockSize;
485
486
    /* Allocate memory for the encrypted secret */
487
0
    UA_ByteString encrypted;
488
0
    UA_StatusCode res = UA_ByteString_allocBuffer(&encrypted, encryptedLength);
489
0
    if(res != UA_STATUSCODE_GOOD)
490
0
        return res;
491
492
    /* Copy the secret and the nonce into the output */
493
0
    UA_Byte *pos = encrypted.data;
494
0
    const UA_Byte *end = &encrypted.data[encrypted.length];
495
0
    res = UA_UInt32_encodeBinary(&length, &pos, end);
496
0
    memcpy(pos, tokenData->data, tokenData->length);
497
0
    memcpy(&pos[tokenData->length], serverSessionNonce.data,
498
0
           serverSessionNonce.length);
499
0
    UA_assert(res == UA_STATUSCODE_GOOD);
500
501
    /* Add padding
502
     *
503
     * 7.36.2.2 Legacy Encrypted Token Secret Format: A Client should not add
504
     * any padding after the secret. If a Client adds padding then all bytes
505
     * shall be zero. A Server shall check for padding added by Clients and
506
     * ensure that all padding bytes are zeros. */
507
0
    size_t paddedLength = plainTextBlockSize * blocks;
508
0
    for(size_t i = totalLength; i < paddedLength; i++)
509
0
        encrypted.data[i] = 0;
510
0
    encrypted.length = paddedLength;
511
512
    /* Encrypt */
513
0
    res = sp->asymEncryptionAlgorithm.encrypt(sp, spContext, &encrypted);
514
0
    if(res != UA_STATUSCODE_GOOD) {
515
0
        UA_ByteString_clear(&encrypted);
516
0
        return res;
517
0
    }
518
519
    /* Replace the tokenData with the output */
520
0
    encrypted.length = encryptedLength;
521
0
    UA_ByteString_clear(tokenData);
522
0
    *tokenData = encrypted;
523
0
    return UA_STATUSCODE_GOOD;
524
0
}
525
526
UA_StatusCode
527
decryptSecretLegacy(const UA_SecurityPolicy *sp, void *spContext,
528
                    const UA_ByteString serverSessionNonce,
529
0
                    UA_ByteString *tokenData) {
530
0
    UA_UInt32 secretLen = 0;
531
0
    UA_ByteString secret, tokenNonce;
532
0
    size_t tokenpos = 0;
533
0
    size_t offset = 0;
534
0
    const UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
535
536
    /* Decrypt the secret */
537
0
    UA_StatusCode res = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
538
0
    if(UA_ByteString_copy(tokenData, &secret) != UA_STATUSCODE_GOOD ||
539
0
       asymEnc->decrypt(sp, spContext, &secret) != UA_STATUSCODE_GOOD)
540
0
        goto cleanup;
541
542
    /* The secret starts with a UInt32 length for the content */
543
0
    if(UA_UInt32_decodeBinary(&secret, &offset, &secretLen) != UA_STATUSCODE_GOOD)
544
0
        goto cleanup;
545
546
    /* The decrypted data must be large enough to include the Encrypted Token
547
     * Secret Format and the length field must indicate enough data to include
548
     * the server nonce. */
549
0
    if(secret.length < sizeof(UA_UInt32) + serverSessionNonce.length ||
550
0
       secret.length < sizeof(UA_UInt32) + secretLen ||
551
0
       secretLen < serverSessionNonce.length)
552
0
        goto cleanup;
553
554
    /* If the Encrypted Token Secret contains padding, the padding must be
555
     * zeroes according to the 1.04.1 specification errata, chapter 3. */
556
0
    for(size_t i = sizeof(UA_UInt32) + secretLen; i < secret.length; i++) {
557
0
        if(secret.data[i] != 0)
558
0
            goto cleanup;
559
0
    }
560
561
    /* The server nonce must match according to the 1.04.1 specification errata,
562
     * chapter 3. */
563
0
    tokenpos = sizeof(UA_UInt32) + secretLen - serverSessionNonce.length;
564
0
    tokenNonce.length = serverSessionNonce.length;
565
0
    tokenNonce.data = &secret.data[tokenpos];
566
0
    if(!UA_ByteString_equal(&serverSessionNonce, &tokenNonce))
567
0
        goto cleanup;
568
569
    /* The password was decrypted successfully. Replace usertoken with the
570
     * decrypted password. The encryptionAlgorithm and policyId fields are left
571
     * in the UserToken as an indication for the AccessControl plugin that
572
     * evaluates the decrypted content. */
573
0
    size_t outLen = secretLen - serverSessionNonce.length;
574
0
    memcpy(tokenData->data, &secret.data[sizeof(UA_UInt32)], outLen);
575
0
    tokenData->length = outLen;
576
0
    res = UA_STATUSCODE_GOOD;
577
578
0
 cleanup:
579
0
    UA_ByteString_clear(&secret);
580
0
    return res;
581
0
}