• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / mender / 1046240096

23 Oct 2023 01:07PM UTC coverage: 80.229% (-0.1%) from 80.369%
1046240096

push

gitlab-ci

oleorhagen
fix(artifact): Add support for verifying our custom EC signature format

This adds support for verifying our custom EC signature marshalling from our
Mender-Artifact format/tool.

Somewhat surprisingly, it turns out that we do not encode the `EC` signature in
any known binary encoding format.

Instead we simply concatenate the integers (r & s) in this instance, into a
binary array, and write it to file.

This brings a host of issues obviously (where hard to understand is just one of
them). The other is that not encoding it in an architecture independent format
is that the signature will only be verified on the architecture it was made (it
needs the right byte-order), so Big- and Little-endian makes a difference here.

To accomodate this, the new client will try and decode both integers in both
Little- and Big-endian format, then encode it into `ASN.1` and `DER`, and then
pass it on to our regular verification code.

Ticket: MEN-6671
Changelog: None

Signed-off-by: Ole Petter <ole.orhagen@northern.tech>

48 of 48 new or added lines in 1 file covered. (100.0%)

6874 of 8568 relevant lines covered (80.23%)

9387.78 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.52
/common/config_parser/config_parser.cpp
1
// Copyright 2023 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14

15
#include <common/config_parser.hpp>
16

17
#include <string>
18
#include <vector>
19
#include <algorithm>
20

21
#include <common/json.hpp>
22
#include <common/log.hpp>
23

24
namespace mender {
25
namespace common {
26
namespace config_parser {
27

28
using namespace std;
29

30
namespace json = mender::common::json;
31
namespace log = mender::common::log;
32

33
const ConfigParserErrorCategoryClass ConfigParserErrorCategory;
34

35
const char *ConfigParserErrorCategoryClass::name() const noexcept {
×
36
        return "ConfigParserErrorCategory";
×
37
}
38

39
string ConfigParserErrorCategoryClass::message(int code) const {
×
40
        switch (code) {
×
41
        case NoError:
42
                return "Success";
×
43
        case ValidationError:
44
                return "Validation error";
×
45
        default:
46
                return "Unknown";
×
47
        }
48
}
49

50
error::Error MakeError(ConfigParserErrorCode code, const string &msg) {
1✔
51
        return error::Error(error_condition(code, ConfigParserErrorCategory), msg);
3✔
52
}
53

54
ExpectedBool MenderConfigFromFile::ValidateServerConfig() const {
6✔
55
        if (server_url.size() != 0 && servers.size() != 0) {
6✔
56
                auto err = MakeError(
57
                        ConfigParserErrorCode::ValidationError,
58
                        "Both 'Servers' AND 'ServerURL given in the configuration. Please set only one of these fields");
2✔
59
                return expected::unexpected(err);
2✔
60
        }
61

62
        if (servers.size() == 0) {
5✔
63
                if (server_url.size() == 0) {
4✔
64
                        log::Warning(
3✔
65
                                "No ServerURL found in the configuration. The client will not be able to download updates");
6✔
66
                }
67
        }
68
        return true;
69
}
70

71
ExpectedBool MenderConfigFromFile::LoadFile(const string &path) {
236✔
72
        const json::ExpectedJson e_cfg_json = json::LoadFromFile(path);
472✔
73
        if (!e_cfg_json) {
236✔
74
                auto err = e_cfg_json.error();
220✔
75
                return expected::unexpected(err);
440✔
76
        }
77

78
        bool applied = false;
79

80
        const json::Json cfg_json = e_cfg_json.value();
16✔
81

82
        json::ExpectedJson e_cfg_value = cfg_json.Get("DeviceTypeFile");
16✔
83
        if (e_cfg_value) {
16✔
84
                const json::Json value_json = e_cfg_value.value();
11✔
85
                const json::ExpectedString e_cfg_string = value_json.GetString();
11✔
86
                if (e_cfg_string) {
11✔
87
                        this->device_type_file = e_cfg_string.value();
11✔
88
                        applied = true;
89
                }
90
        }
91

92
        e_cfg_value = cfg_json.Get("ServerCertificate");
32✔
93
        if (e_cfg_value) {
16✔
94
                const json::Json value_json = e_cfg_value.value();
7✔
95
                const json::ExpectedString e_cfg_string = value_json.GetString();
7✔
96
                if (e_cfg_string) {
7✔
97
                        this->server_certificate = e_cfg_string.value();
7✔
98
                        applied = true;
99
                }
100
        }
101

102
        e_cfg_value = cfg_json.Get("ServerURL");
32✔
103
        if (e_cfg_value) {
16✔
104
                const json::Json value_json = e_cfg_value.value();
11✔
105
                const json::ExpectedString e_cfg_string = value_json.GetString();
11✔
106
                if (e_cfg_string) {
11✔
107
                        this->server_url = e_cfg_string.value();
11✔
108
                        applied = true;
109
                }
110
        }
111

112
        e_cfg_value = cfg_json.Get("UpdateLogPath");
32✔
113
        if (e_cfg_value) {
16✔
114
                const json::Json value_json = e_cfg_value.value();
8✔
115
                const json::ExpectedString e_cfg_string = value_json.GetString();
8✔
116
                if (e_cfg_string) {
8✔
117
                        this->update_log_path = e_cfg_string.value();
8✔
118
                        applied = true;
119
                }
120
        }
121

122
        e_cfg_value = cfg_json.Get("TenantToken");
32✔
123
        if (e_cfg_value) {
16✔
124
                const json::Json value_json = e_cfg_value.value();
7✔
125
                const json::ExpectedString e_cfg_string = value_json.GetString();
7✔
126
                if (e_cfg_string) {
7✔
127
                        this->tenant_token = e_cfg_string.value();
7✔
128
                        applied = true;
129
                }
130
        }
131

132
        e_cfg_value = cfg_json.Get("DaemonLogLevel");
32✔
133
        if (e_cfg_value) {
16✔
134
                const json::Json value_json = e_cfg_value.value();
9✔
135
                const json::ExpectedString e_cfg_string = value_json.GetString();
9✔
136
                if (e_cfg_string) {
9✔
137
                        this->daemon_log_level = e_cfg_string.value();
9✔
138
                        applied = true;
139
                }
140
        }
141

142
        /* Boolean values now */
143
        e_cfg_value = cfg_json.Get("SkipVerify");
32✔
144
        if (e_cfg_value) {
16✔
145
                const json::Json value_json = e_cfg_value.value();
9✔
146
                const json::ExpectedBool e_cfg_bool = value_json.GetBool();
9✔
147
                if (e_cfg_bool) {
9✔
148
                        this->skip_verify = e_cfg_bool.value();
9✔
149
                        applied = true;
150
                }
151
        }
152

153
        e_cfg_value = cfg_json.Get("UpdatePollIntervalSeconds");
32✔
154
        if (e_cfg_value) {
16✔
155
                const json::Json value_json = e_cfg_value.value();
7✔
156
                const auto e_cfg_int = value_json.GetInt();
7✔
157
                if (e_cfg_int) {
7✔
158
                        this->update_poll_interval_seconds = e_cfg_int.value();
7✔
159
                        applied = true;
160
                }
161
        }
162

163
        e_cfg_value = cfg_json.Get("InventoryPollIntervalSeconds");
32✔
164
        if (e_cfg_value) {
16✔
165
                const json::Json value_json = e_cfg_value.value();
7✔
166
                const auto e_cfg_int = value_json.GetInt();
7✔
167
                if (e_cfg_int) {
7✔
168
                        this->inventory_poll_interval_seconds = e_cfg_int.value();
7✔
169
                        applied = true;
170
                }
171
        }
172

173
        e_cfg_value = cfg_json.Get("RetryPollIntervalSeconds");
32✔
174
        if (e_cfg_value) {
16✔
175
                const json::Json value_json = e_cfg_value.value();
7✔
176
                const auto e_cfg_int = value_json.GetInt();
7✔
177
                if (e_cfg_int) {
7✔
178
                        this->retry_poll_interval_seconds = e_cfg_int.value();
7✔
179
                        applied = true;
180
                }
181
        }
182

183
        e_cfg_value = cfg_json.Get("RetryPollCount");
32✔
184
        if (e_cfg_value) {
16✔
185
                const json::Json value_json = e_cfg_value.value();
7✔
186
                const auto e_cfg_int = value_json.GetInt();
7✔
187
                if (e_cfg_int) {
7✔
188
                        this->retry_poll_count = e_cfg_int.value();
7✔
189
                        applied = true;
190
                }
191
        }
192

193
        e_cfg_value = cfg_json.Get("StateScriptTimeoutSeconds");
32✔
194
        if (e_cfg_value) {
16✔
195
                const json::Json value_json = e_cfg_value.value();
7✔
196
                const auto e_cfg_int = value_json.GetInt();
7✔
197
                if (e_cfg_int) {
7✔
198
                        this->state_script_timeout_seconds = e_cfg_int.value();
7✔
199
                        applied = true;
200
                }
201
        }
202

203
        e_cfg_value = cfg_json.Get("StateScriptRetryTimeoutSeconds");
32✔
204
        if (e_cfg_value) {
16✔
205
                const json::Json value_json = e_cfg_value.value();
7✔
206
                const auto e_cfg_int = value_json.GetInt();
7✔
207
                if (e_cfg_int) {
7✔
208
                        this->state_script_retry_timeout_seconds = e_cfg_int.value();
7✔
209
                        applied = true;
210
                }
211
        }
212

213
        e_cfg_value = cfg_json.Get("StateScriptRetryIntervalSeconds");
32✔
214
        if (e_cfg_value) {
16✔
215
                const json::Json value_json = e_cfg_value.value();
7✔
216
                const auto e_cfg_int = value_json.GetInt();
7✔
217
                if (e_cfg_int) {
7✔
218
                        this->state_script_retry_interval_seconds = e_cfg_int.value();
7✔
219
                        applied = true;
220
                }
221
        }
222

223
        e_cfg_value = cfg_json.Get("ModuleTimeoutSeconds");
32✔
224
        if (e_cfg_value) {
16✔
225
                const json::Json value_json = e_cfg_value.value();
7✔
226
                const auto e_cfg_int = value_json.GetInt();
7✔
227
                if (e_cfg_int) {
7✔
228
                        this->module_timeout_seconds = e_cfg_int.value();
7✔
229
                        applied = true;
230
                }
231
        }
232

233

234
        e_cfg_value = cfg_json.Get("ArtifactVerifyKeys");
32✔
235
        if (e_cfg_value) {
16✔
236
                const json::Json value_array = e_cfg_value.value();
9✔
237
                const json::ExpectedSize e_n_items = value_array.GetArraySize();
9✔
238
                if (e_n_items) {
9✔
239
                        for (size_t i = 0; i < e_n_items.value(); i++) {
33✔
240
                                const json::ExpectedJson e_array_item = value_array.Get(i);
24✔
241
                                if (e_array_item) {
24✔
242
                                        const json::ExpectedString e_item_string = e_array_item.value().GetString();
24✔
243
                                        if (e_item_string) {
24✔
244
                                                const string item_value = e_item_string.value();
24✔
245
                                                if (count(
24✔
246
                                                                this->artifact_verify_keys.begin(),
247
                                                                this->artifact_verify_keys.end(),
248
                                                                item_value)
249
                                                        == 0) {
250
                                                        this->artifact_verify_keys.push_back(item_value);
24✔
251
                                                        applied = true;
252
                                                }
253
                                        }
254
                                }
255
                        }
256
                }
257
        }
258

259
        e_cfg_value = cfg_json.Get("ArtifactVerifyKey");
32✔
260
        if (e_cfg_value) {
16✔
261
                const json::Json value_json = e_cfg_value.value();
2✔
262
                const json::ExpectedString e_cfg_string = value_json.GetString();
2✔
263
                if (e_cfg_string) {
2✔
264
                        if (artifact_verify_keys.size() != 0) {
2✔
265
                                auto err = MakeError(
266
                                        ConfigParserErrorCode::ValidationError,
267
                                        "Both 'ArtifactVerifyKey' and 'ArtifactVerifyKeys' are set");
2✔
268
                                return expected::unexpected(err);
2✔
269
                        }
270
                        this->artifact_verify_keys.push_back(e_cfg_string.value());
1✔
271
                        applied = true;
272
                }
273
        }
274

275
        e_cfg_value = cfg_json.Get("Servers");
30✔
276
        if (e_cfg_value) {
15✔
277
                const json::Json value_array = e_cfg_value.value();
8✔
278
                const json::ExpectedSize e_n_items = value_array.GetArraySize();
8✔
279
                if (e_n_items) {
8✔
280
                        for (size_t i = 0; i < e_n_items.value(); i++) {
23✔
281
                                const json::ExpectedJson e_array_item = value_array.Get(i);
15✔
282
                                if (e_array_item) {
15✔
283
                                        const json::ExpectedJson e_item_json = e_array_item.value().Get("ServerURL");
15✔
284
                                        if (e_item_json) {
15✔
285
                                                const json::ExpectedString e_item_string = e_item_json.value().GetString();
15✔
286
                                                if (e_item_string) {
15✔
287
                                                        const string item_value = e_item_string.value();
15✔
288
                                                        if (count(this->servers.begin(), this->servers.end(), item_value)
15✔
289
                                                                == 0) {
290
                                                                this->servers.push_back(std::move(item_value));
15✔
291
                                                                applied = true;
292
                                                        }
293
                                                }
294
                                        }
295
                                }
296
                        }
297
                }
298
        }
299

300
        /* Last but not least, complex values */
301
        e_cfg_value = cfg_json.Get("HttpsClient");
30✔
302
        if (e_cfg_value) {
15✔
303
                const json::Json value_json = e_cfg_value.value();
8✔
304
                json::ExpectedJson e_cfg_subval = value_json.Get("Certificate");
8✔
305
                if (e_cfg_subval) {
8✔
306
                        const json::Json subval_json = e_cfg_subval.value();
8✔
307
                        const json::ExpectedString e_cfg_string = subval_json.GetString();
8✔
308
                        if (e_cfg_string) {
8✔
309
                                this->https_client.certificate = e_cfg_string.value();
8✔
310
                                applied = true;
311
                        }
312
                }
313

314
                e_cfg_subval = value_json.Get("Key");
16✔
315
                if (e_cfg_subval) {
8✔
316
                        const json::Json subval_json = e_cfg_subval.value();
7✔
317
                        const json::ExpectedString e_cfg_string = subval_json.GetString();
7✔
318
                        if (e_cfg_string) {
7✔
319
                                this->https_client.key = e_cfg_string.value();
7✔
320
                                applied = true;
321
                        }
322
                }
323

324
                e_cfg_subval = value_json.Get("SSLEngine");
16✔
325
                if (e_cfg_subval) {
8✔
326
                        const json::Json subval_json = e_cfg_subval.value();
7✔
327
                        const json::ExpectedString e_cfg_string = subval_json.GetString();
7✔
328
                        if (e_cfg_string) {
7✔
329
                                this->https_client.ssl_engine = e_cfg_string.value();
7✔
330
                                applied = true;
331
                        }
332
                }
333
        }
334

335
        e_cfg_value = cfg_json.Get("Security");
30✔
336
        if (e_cfg_value) {
15✔
337
                const json::Json value_json = e_cfg_value.value();
7✔
338
                json::ExpectedJson e_cfg_subval = value_json.Get("AuthPrivateKey");
7✔
339
                if (e_cfg_subval) {
7✔
340
                        const json::Json subval_json = e_cfg_subval.value();
7✔
341
                        const json::ExpectedString e_cfg_string = subval_json.GetString();
7✔
342
                        if (e_cfg_string) {
7✔
343
                                this->security.auth_private_key = e_cfg_string.value();
7✔
344
                                applied = true;
345
                        }
346
                }
347

348
                e_cfg_subval = value_json.Get("SSLEngine");
14✔
349
                if (e_cfg_subval) {
7✔
350
                        const json::Json subval_json = e_cfg_subval.value();
7✔
351
                        const json::ExpectedString e_cfg_string = subval_json.GetString();
7✔
352
                        if (e_cfg_string) {
7✔
353
                                this->security.ssl_engine = e_cfg_string.value();
7✔
354
                                applied = true;
355
                        }
356
                }
357
        }
358

359
        e_cfg_value = cfg_json.Get("Connectivity");
30✔
360
        if (e_cfg_value) {
15✔
361
                const json::Json value_json = e_cfg_value.value();
8✔
362
                json::ExpectedJson e_cfg_subval = value_json.Get("DisableKeepAlive");
8✔
363
                if (e_cfg_subval) {
8✔
364
                        const json::Json subval_json = e_cfg_subval.value();
8✔
365
                        const json::ExpectedBool e_cfg_bool = subval_json.GetBool();
8✔
366
                        if (e_cfg_bool) {
8✔
367
                                this->connectivity.disable_keep_alive = e_cfg_bool.value();
8✔
368
                                applied = true;
369
                        }
370
                }
371
        }
372

373
        return applied;
374
}
375

376
void MenderConfigFromFile::Reset() {
1✔
377
        *this = MenderConfigFromFile();
1✔
378
}
1✔
379

380
ExpectedBool MenderConfigFromFile::ValidateConfig() {
3✔
381
        auto server_conf = this->ValidateServerConfig();
3✔
382
        if (!server_conf) {
3✔
383
                return server_conf;
384
        }
385

386
        return true;
387
}
388

389

390

391
} // namespace config_parser
392
} // namespace common
393
} // namespace mender
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc