Coverage Report

Created: 2025-08-03 06:13

/src/S2OPC/src/PubSub/security/sopc_pubsub_security.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Licensed to Systerel under one or more contributor license
3
 * agreements. See the NOTICE file distributed with this work
4
 * for additional information regarding copyright ownership.
5
 * Systerel licenses this file to you under the Apache
6
 * License, Version 2.0 (the "License"); you may not use this
7
 * file except in compliance with the License. You may obtain
8
 * a copy of the License at
9
 *
10
 *   http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing,
13
 * software distributed under the License is distributed on an
14
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
 * KIND, either express or implied.  See the License for the
16
 * specific language governing permissions and limitations
17
 * under the License.
18
 */
19
20
#include "sopc_pubsub_security.h"
21
#include "sopc_assert.h"
22
#include "sopc_buffer.h"
23
#include "sopc_crypto_provider.h"
24
#include "sopc_encoder.h"
25
#include "sopc_mem_alloc.h"
26
#include "sopc_pubsub_constants.h"
27
#include "sopc_secret_buffer.h"
28
29
/* Spec OPCUA Part 14 define size of Nonce ( group, nonce, sequence number */
30
#define SOPC_PUBSUB_SECURITY_RANDOM_LENGTH 4
31
32
SOPC_Buffer* SOPC_PubSub_Security_Encrypt(const SOPC_PubSub_SecurityType* security, SOPC_Buffer* payload)
33
0
{
34
0
    if (NULL == security || NULL == security->provider || NULL == security->groupKeys || NULL == payload)
35
0
    {
36
0
        return NULL;
37
0
    }
38
0
    SOPC_ReturnStatus status;
39
0
    uint32_t payload_size = payload->length;
40
0
    uint8_t* encrypted = SOPC_Malloc(payload->length * sizeof(uint8_t));
41
0
    if (NULL == encrypted)
42
0
    {
43
0
        return NULL;
44
0
    }
45
46
0
    uint32_t encrypted_size;
47
0
    status = SOPC_CryptoProvider_SymmetricGetLength_Encryption(security->provider, payload_size, &encrypted_size);
48
0
    if (SOPC_STATUS_OK != status)
49
0
    {
50
0
        SOPC_Free(encrypted);
51
0
        return NULL;
52
0
    }
53
54
0
    uint32_t lengthMessageRandom;
55
0
    status = SOPC_CryptoProvider_PubSubGetLength_MessageRandom(security->provider, &lengthMessageRandom);
56
0
    if (SOPC_STATUS_OK != status)
57
0
    {
58
0
        SOPC_Free(encrypted);
59
0
        return NULL;
60
0
    }
61
    // Check with length in UADP  (OPC UA Spec Part 14)
62
0
    SOPC_ASSERT(SOPC_PUBSUB_SECURITY_RANDOM_LENGTH == lengthMessageRandom);
63
0
    status = SOPC_CryptoProvider_PubSubCrypt(security->provider, payload->data, payload->length,
64
0
                                             security->groupKeys->encryptKey, security->groupKeys->keyNonce,
65
0
                                             security->msgNonceRandom, lengthMessageRandom, security->sequenceNumber,
66
0
                                             encrypted, encrypted_size);
67
68
0
    if (SOPC_STATUS_OK != status)
69
0
    {
70
0
        SOPC_Free(encrypted);
71
0
        return NULL;
72
0
    }
73
74
0
    SOPC_Buffer* result = SOPC_Buffer_Attach(encrypted, encrypted_size);
75
0
    if (NULL == result)
76
0
    {
77
0
        SOPC_Free(encrypted);
78
0
        return NULL;
79
0
    }
80
81
0
    return result;
82
0
}
83
84
SOPC_Buffer* SOPC_PubSub_Security_Decrypt(const SOPC_PubSub_SecurityType* security, SOPC_Buffer* src, uint32_t len)
85
0
{
86
0
    if (NULL == security || NULL == src || len == 0 || NULL == src->data || src->position + len > src->length)
87
0
    {
88
0
        return NULL;
89
0
    }
90
91
    // Create a buffer containing encrypted data
92
0
    SOPC_Buffer* buffer_encrypted = SOPC_Buffer_Create(len);
93
0
    if (NULL == buffer_encrypted)
94
0
    {
95
0
        return NULL;
96
0
    }
97
0
    SOPC_ReturnStatus result = SOPC_Buffer_Write(buffer_encrypted, &src->data[src->position], len);
98
0
    if (SOPC_STATUS_OK != result)
99
0
    {
100
0
        SOPC_Buffer_Delete(buffer_encrypted);
101
0
        return NULL;
102
0
    }
103
104
    // Decrypt is encrypt
105
0
    SOPC_Buffer* buffer_clear = SOPC_PubSub_Security_Encrypt(security, buffer_encrypted);
106
107
0
    SOPC_Buffer_Delete(buffer_encrypted);
108
0
    return buffer_clear;
109
0
}
110
111
// return size of signature. Size given in Octet
112
SOPC_ReturnStatus SOPC_PubSub_Security_GetSignSize(const SOPC_PubSub_SecurityType* security,
113
                                                   bool enabled,
114
                                                   uint32_t* length)
115
0
{
116
0
    if (NULL == security || NULL == length)
117
0
    {
118
0
        return SOPC_STATUS_INVALID_PARAMETERS;
119
0
    }
120
0
    SOPC_ReturnStatus status = SOPC_STATUS_OK;
121
0
    if (!enabled)
122
0
    {
123
0
        *length = 0;
124
0
    }
125
0
    else
126
0
    {
127
0
        status = SOPC_CryptoProvider_SymmetricGetLength_Signature(security->provider, length);
128
0
    }
129
0
    return status;
130
0
}
131
/* Sign from 0 to current position and add signature after current position */
132
SOPC_ReturnStatus SOPC_PubSub_Security_Sign(const SOPC_PubSub_SecurityType* security, SOPC_Buffer* src)
133
0
{
134
0
    if (NULL == security || NULL == security->groupKeys || NULL == src)
135
0
    {
136
0
        return SOPC_STATUS_INVALID_PARAMETERS;
137
0
    }
138
0
    uint32_t length;
139
0
    SOPC_ReturnStatus status = SOPC_CryptoProvider_SymmetricGetLength_Signature(security->provider, &length);
140
0
    if (SOPC_STATUS_OK != status)
141
0
    {
142
0
        return status;
143
0
    }
144
0
    uint8_t* signature = SOPC_Calloc(length, sizeof(uint8_t));
145
0
    if (NULL == signature)
146
0
    {
147
0
        return SOPC_STATUS_OUT_OF_MEMORY;
148
0
    }
149
150
0
    status = SOPC_CryptoProvider_SymmetricSign(security->provider, src->data, src->position,
151
0
                                               security->groupKeys->signingKey, signature, length);
152
0
    if (SOPC_STATUS_OK == status)
153
0
    {
154
0
        status = SOPC_Buffer_Write(src, signature, length);
155
0
    }
156
0
    SOPC_Free(signature);
157
0
    return status;
158
0
}
159
160
bool SOPC_PubSub_Security_Verify(const SOPC_PubSub_SecurityType* security, SOPC_Buffer* src, uint32_t payloadPosition)
161
0
{
162
0
    if (NULL == security || NULL == security->groupKeys || NULL == src || NULL == src->data)
163
0
    {
164
0
        return false;
165
0
    }
166
167
0
    uint32_t sizeSignature;
168
0
    SOPC_ReturnStatus status = SOPC_PubSub_Security_GetSignSize(security, true, &sizeSignature);
169
0
    if (SOPC_STATUS_OK != status || sizeSignature >= src->length)
170
0
    {
171
0
        return false;
172
0
    }
173
    // Sign from begining of buffer to begining of signature
174
0
    uint32_t lenPayload = (src->length - payloadPosition) - sizeSignature;
175
0
    status = SOPC_CryptoProvider_SymmetricVerify(security->provider, src->data + payloadPosition, lenPayload,
176
0
                                                 security->groupKeys->signingKey,
177
0
                                                 &src->data[payloadPosition + lenPayload], sizeSignature);
178
0
    return (SOPC_STATUS_OK == status);
179
0
}
180
181
void SOPC_PubSub_Security_Clear(SOPC_PubSub_SecurityType* security)
182
0
{
183
0
    if (NULL != security)
184
0
    {
185
0
        SOPC_Free(security->securityGroupId);
186
0
        security->securityGroupId = NULL;
187
0
        security->mode = SOPC_SecurityMode_Invalid;
188
0
        SOPC_PubSubSKS_Keys_Delete(security->groupKeys);
189
0
        SOPC_Free(security->groupKeys);
190
0
        security->groupKeys = NULL;
191
0
        SOPC_Free(security->msgNonceRandom);
192
0
        security->msgNonceRandom = NULL;
193
0
        SOPC_CryptoProvider_Free(security->provider);
194
0
    }
195
0
}
196
197
SOPC_ReturnStatus SOPC_PubSub_Security_Write_Nonce(const SOPC_PubSub_SecurityType* security,
198
                                                   SOPC_Buffer* dst,
199
                                                   uint8_t nonceRandomLength)
200
0
{
201
    // See OPCUA Spec Part 14 - Table 75 - revision 1.04
202
    // The only algorithms used is AES-CTR for now
203
0
    const uint8_t AES_CTR_nonceRandomLength = 4;
204
0
    if (NULL == security || NULL == dst || AES_CTR_nonceRandomLength != nonceRandomLength)
205
0
    {
206
0
        return SOPC_STATUS_INVALID_PARAMETERS;
207
0
    }
208
209
    // Random bytes
210
0
    SOPC_ReturnStatus status = SOPC_Buffer_Write(dst, security->msgNonceRandom, (uint32_t) nonceRandomLength);
211
212
0
    if (SOPC_STATUS_OK == status)
213
0
    {
214
        // Sequence Number
215
0
        status = SOPC_UInt32_Write(&security->sequenceNumber, dst, 0);
216
0
    }
217
0
    return status;
218
0
}
219
220
SOPC_ExposedBuffer* SOPC_PubSub_Security_Random(const SOPC_CryptoProvider* provider)
221
0
{
222
0
    uint32_t length;
223
0
    SOPC_ReturnStatus status = SOPC_CryptoProvider_PubSubGetLength_MessageRandom(provider, &length);
224
0
    if (SOPC_STATUS_OK != status)
225
0
    {
226
0
        return NULL;
227
0
    }
228
229
0
    SOPC_ExposedBuffer* ppBuffer;
230
0
    status = SOPC_CryptoProvider_GenerateRandomBytes(provider, length, &ppBuffer);
231
0
    if (SOPC_STATUS_OK != status)
232
0
    {
233
0
        return NULL;
234
0
    }
235
0
    return ppBuffer;
236
0
}