edhoc 1.2.3 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/binding.gyp +2 -2
  2. package/dist/edhoc.d.ts +4 -0
  3. package/dist/edhoc.d.ts.map +1 -1
  4. package/include/{LibEDHOC.h → Binding.h} +60 -40
  5. package/include/EdhocComposeAsyncWorker.h +8 -22
  6. package/include/EdhocCredentialManager.h +9 -25
  7. package/include/EdhocCryptoManager.h +27 -43
  8. package/include/EdhocEadManager.h +3 -4
  9. package/include/EdhocExportOscoreAsyncWorker.h +10 -27
  10. package/include/EdhocKeyExporterAsyncWorker.h +8 -28
  11. package/include/EdhocKeyUpdateAsyncWorker.h +7 -24
  12. package/include/EdhocProcessAsyncWorker.h +11 -36
  13. package/include/RunningContext.h +102 -0
  14. package/include/Utils.h +2 -46
  15. package/package.json +1 -2
  16. package/prebuilds/android-arm/edhoc.armv7.node +0 -0
  17. package/prebuilds/android-arm64/edhoc.armv8.node +0 -0
  18. package/prebuilds/darwin-arm64/edhoc.node +0 -0
  19. package/prebuilds/darwin-x64/edhoc.node +0 -0
  20. package/prebuilds/linux-arm/edhoc.armv6.node +0 -0
  21. package/prebuilds/linux-arm/edhoc.armv7.node +0 -0
  22. package/prebuilds/linux-arm64/edhoc.armv8.node +0 -0
  23. package/prebuilds/linux-x64/edhoc.glibc.node +0 -0
  24. package/prebuilds/linux-x64/edhoc.musl.node +0 -0
  25. package/prebuilds/win32-ia32/edhoc.node +0 -0
  26. package/prebuilds/win32-x64/edhoc.node +0 -0
  27. package/src/Binding.cpp +434 -0
  28. package/src/EdhocComposeAsyncWorker.cpp +39 -57
  29. package/src/EdhocCredentialManager.cpp +58 -93
  30. package/src/EdhocCryptoManager.cpp +181 -400
  31. package/src/EdhocEadManager.cpp +13 -13
  32. package/src/EdhocExportOscoreAsyncWorker.cpp +29 -45
  33. package/src/EdhocKeyExporterAsyncWorker.cpp +19 -37
  34. package/src/EdhocKeyUpdateAsyncWorker.cpp +15 -33
  35. package/src/EdhocProcessAsyncWorker.cpp +82 -96
  36. package/src/RunningContext.cpp +95 -0
  37. package/src/Utils.cpp +2 -34
  38. package/test/basic.test.ts +57 -3
  39. package/include/UserContext.h +0 -78
  40. package/src/LibEDHOC.cpp +0 -418
  41. package/test/errors.test.ts +0 -129
package/include/Utils.h CHANGED
@@ -2,12 +2,11 @@
2
2
  #define UTILS_H
3
3
 
4
4
  #include <napi.h>
5
-
6
5
  #include <cstdint>
7
6
  #include <future>
8
- #include <iostream>
9
7
  #include <string>
10
8
  #include <vector>
9
+
11
10
  extern "C" {
12
11
  #include "edhoc.h"
13
12
  }
@@ -22,49 +21,6 @@ extern "C" {
22
21
  */
23
22
  class Utils {
24
23
  public:
25
- using SuccessHandler = std::function<void(Napi::Env, Napi::Value)>;
26
- using ErrorHandler = std::function<void(Napi::Env, Napi::Error)>;
27
-
28
- /**
29
- * Invokes a JavaScript function with promise handling.
30
- * The function is called with the specified arguments, and the result is
31
- * passed to a callback function.
32
- *
33
- * @param env The N-API environment handle.
34
- * @param jsObject The N-API object representing the JavaScript class.
35
- * @param jsCallback The N-API function object to call.
36
- * @param args A vector of N-API values representing the arguments to pass to
37
- * the function.
38
- * @param callbackLambda A lambda function to handle the result of the
39
- * function call.
40
- */
41
- static void InvokeJSFunctionWithPromiseHandling(Napi::Env env,
42
- Napi::Object jsObject,
43
- Napi::Function jsCallback,
44
- const std::vector<napi_value>& args,
45
- SuccessHandler successLambda,
46
- ErrorHandler errorLambda);
47
-
48
- /**
49
- * Creates a promise error handler for a given promise.
50
- *
51
- * @tparam T The type of the promise.
52
- * @param promise The promise to handle errors for.
53
- * @return A lambda function that sets the exception on the promise.
54
- */
55
- template <typename T>
56
- static ErrorHandler CreatePromiseErrorHandler(std::promise<T>& promise, T defaultValue, Napi::Error& lastError) {
57
- return [&promise, defaultValue, &lastError](Napi::Env env, Napi::Error error) {
58
- if (!error.IsEmpty()) {
59
- error.ThrowAsJavaScriptException();
60
- }
61
- if (env.IsExceptionPending()) {
62
- lastError = env.GetAndClearPendingException();
63
- }
64
- promise.set_value(defaultValue);
65
- };
66
- }
67
-
68
24
  /**
69
25
  * Converts a JavaScript value to an EDHOC connection ID structure.
70
26
  * The input can be a number or a buffer.
@@ -95,7 +51,7 @@ class Utils {
95
51
  template <typename EnumType>
96
52
  static EnumType ConvertToEnum(const Napi::Value& value) {
97
53
  if (!value.IsNumber()) {
98
- Napi::TypeError::New(value.Env(), "Input value must be a number").ThrowAsJavaScriptException();
54
+ throw Napi::TypeError::New(value.Env(), "Input value must be a number");
99
55
  }
100
56
  return static_cast<EnumType>(value.As<Napi::Number>().Int32Value());
101
57
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "edhoc",
3
3
  "description": "A Node.js implementation of EDHOC (Ephemeral Diffie-Hellman Over COSE) protocol for lightweight authenticated key exchange in IoT and other constrained environments.",
4
- "version": "1.2.3",
4
+ "version": "1.3.1",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "author": "Marek Serafin <marek@serafin.email>",
@@ -53,7 +53,6 @@
53
53
  "@semantic-release/git": "^10.0.1",
54
54
  "@semantic-release/github": "^10.1.1",
55
55
  "@types/elliptic": "^6.4.18",
56
- "@types/eslint__js": "^8.42.3",
57
56
  "@types/jest": "^29.5.14",
58
57
  "@types/node": "^22.13.4",
59
58
  "eslint": "^8.57.0",
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,434 @@
1
+ #include "Binding.h"
2
+
3
+ #include <iostream>
4
+ #include <thread>
5
+
6
+ #include "EdhocComposeAsyncWorker.h"
7
+ #include "EdhocExportOscoreAsyncWorker.h"
8
+ #include "EdhocKeyExporterAsyncWorker.h"
9
+ #include "EdhocKeyUpdateAsyncWorker.h"
10
+ #include "EdhocProcessAsyncWorker.h"
11
+ #include "Suites.h"
12
+ #include "Utils.h"
13
+
14
+ static constexpr const char* kErrorFailedToInitializeEdhocContext = "Failed to initialize EDHOC context.";
15
+ static constexpr const char* kErrorFailedToSetEdhocConnectionId = "Failed to set EDHOC Connection ID.";
16
+ static constexpr const char* kErrorFailedToSetEdhocMethod = "Failed to set EDHOC Method.";
17
+ static constexpr const char* kErrorArraySuiteIndexesExpected = "Array of suite indexes expected";
18
+ static constexpr const char* kErrorArrayMethodIndexesExpected = "Array of method indexes expected";
19
+ static constexpr const char* kErrorInvalidCipherSuiteIndex = "Invalid cipher suite index";
20
+ static constexpr const char* kErrorFailedToSetCipherSuites = "Failed to set cipher suites";
21
+ static constexpr const char* kErrorExpectedFirstArgumentToBeBuffer = "Expected first argument to be a Buffer";
22
+ static constexpr const char* kErrorExpectedArgumentToBeNumber = "Expected argument to be a number";
23
+ static constexpr const char* kErrorExpectedAFunction = "Expected a function";
24
+
25
+ Edhoc::Edhoc(const Napi::CallbackInfo& info) : Napi::ObjectWrap<Edhoc>(info) {
26
+ Napi::Env env = info.Env();
27
+ Napi::HandleScope scope(env);
28
+
29
+ // Get the JS object
30
+ Napi::Object jsEdhoc = info.This().As<Napi::Object>();
31
+
32
+ // Crypto Manager
33
+ Napi::Object jsCryptoManager = info[4].As<Napi::Object>();
34
+ this->cryptoManager_ = std::make_unique<EdhocCryptoManager>(jsCryptoManager, jsEdhoc);
35
+
36
+ // Credentials
37
+ Napi::Object jsCredentialManager = info[3].As<Napi::Object>();
38
+ this->credentialManager_ = std::make_unique<EdhocCredentialManager>(jsCredentialManager, jsEdhoc);
39
+
40
+ // EAD
41
+ this->eadManager_ = std::make_unique<EdhocEadManager>();
42
+
43
+ // Reset the EDHOC context
44
+ this->Reset(info);
45
+
46
+ // Connection ID, Methods, and Suites
47
+ SetCID(info, info[0]);
48
+ SetMethods(info, info[1]);
49
+ SetCipherSuites(info, info[2]);
50
+ }
51
+
52
+ void Edhoc::Reset(const Napi::CallbackInfo& info) {
53
+ Napi::Env env = info.Env();
54
+ Napi::HandleScope scope(env);
55
+
56
+ bool isInitialized = edhocContext_ != nullptr;
57
+
58
+ // Get the Connection ID, Methods, and Suites
59
+ Napi::Value cid = env.Null();
60
+ Napi::Value methods = env.Null();
61
+ Napi::Value suites = env.Null();
62
+
63
+ if (isInitialized) {
64
+ cid = this->GetCID(info);
65
+ methods = this->GetMethods(info);
66
+ suites = this->GetCipherSuites(info);
67
+ }
68
+
69
+ // Initialize EDHOC context
70
+ edhocContext_ = std::make_unique<edhoc_context>();
71
+
72
+ if (edhoc_context_init(edhocContext_.get()) != EDHOC_SUCCESS) {
73
+ Napi::TypeError::New(env, kErrorFailedToInitializeEdhocContext)
74
+ .ThrowAsJavaScriptException();
75
+ }
76
+
77
+ // Bind all managers
78
+ if (edhoc_bind_keys(edhocContext_.get(), &this->cryptoManager_.get()->keys) != EDHOC_SUCCESS ||
79
+ edhoc_bind_crypto(edhocContext_.get(), &this->cryptoManager_.get()->crypto) != EDHOC_SUCCESS ||
80
+ edhoc_bind_credentials(edhocContext_.get(), &this->credentialManager_.get()->credentials) != EDHOC_SUCCESS ||
81
+ edhoc_bind_ead(edhocContext_.get(), &this->eadManager_.get()->ead) != EDHOC_SUCCESS)
82
+ {
83
+ Napi::TypeError::New(env, kErrorFailedToInitializeEdhocContext)
84
+ .ThrowAsJavaScriptException();
85
+ }
86
+
87
+ // If the previous context was initialized, copy the Connection ID, Methods, and Suites
88
+ if (isInitialized) {
89
+ this->SetCID(info, cid);
90
+ this->SetMethods(info, methods);
91
+ this->SetCipherSuites(info, suites);
92
+ }
93
+
94
+ // Logger
95
+ edhocContext_->logger = Edhoc::Logger;
96
+ }
97
+
98
+ Edhoc::~Edhoc() {
99
+ // Reset the EDHOC context
100
+ }
101
+
102
+ Napi::Value Edhoc::GetCID(const Napi::CallbackInfo& info) {
103
+ return Utils::CreateJsValueFromEdhocCid(info.Env(), cid_);
104
+ }
105
+
106
+ void Edhoc::SetCID(const Napi::CallbackInfo& info, const Napi::Value& value) {
107
+ cid_ = Utils::ConvertJsValueToEdhocCid(value);
108
+ int result = edhoc_set_connection_id(edhocContext_.get(), &cid_);
109
+ if (result != EDHOC_SUCCESS) {
110
+ Napi::TypeError::New(info.Env(), kErrorFailedToSetEdhocConnectionId).ThrowAsJavaScriptException();
111
+ }
112
+ }
113
+
114
+ Napi::Value Edhoc::GetPeerCID(const Napi::CallbackInfo& info) {
115
+ return Utils::CreateJsValueFromEdhocCid(info.Env(), edhocContext_->EDHOC_PRIVATE(peer_cid));
116
+ }
117
+
118
+ Napi::Value Edhoc::GetMethods(const Napi::CallbackInfo& info) {
119
+ Napi::Env env = info.Env();
120
+ Napi::Array result = Napi::Array::New(env, edhocContext_->EDHOC_PRIVATE(method_len));
121
+ for (size_t i = 0; i < edhocContext_->EDHOC_PRIVATE(method_len); i++) {
122
+ result.Set(i, Napi::Number::New(env, edhocContext_->EDHOC_PRIVATE(method)[i]));
123
+ }
124
+ return result;
125
+ }
126
+
127
+ void Edhoc::SetMethods(const Napi::CallbackInfo& info, const Napi::Value& value) {
128
+ Napi::Env env = info.Env();
129
+
130
+ if (!value.IsArray()) {
131
+ Napi::TypeError::New(env, kErrorArrayMethodIndexesExpected)
132
+ .ThrowAsJavaScriptException();
133
+ }
134
+
135
+ const auto jsArray = value.As<Napi::Array>();
136
+ std::vector<edhoc_method> methods;
137
+ methods.reserve(jsArray.Length());
138
+
139
+ for (uint32_t i = 0; i < jsArray.Length(); i++) {
140
+ methods.push_back(static_cast<edhoc_method>(jsArray.Get(i).As<Napi::Number>().Int32Value()));
141
+ }
142
+
143
+ int result = edhoc_set_methods(edhocContext_.get(), methods.data(), methods.size());
144
+ if (result != EDHOC_SUCCESS) {
145
+ Napi::TypeError::New(env, kErrorFailedToSetEdhocMethod)
146
+ .ThrowAsJavaScriptException();
147
+ }
148
+ }
149
+
150
+ Napi::Value Edhoc::GetSelectedMethod(const Napi::CallbackInfo& info) {
151
+ return Napi::Number::New(info.Env(), edhocContext_->EDHOC_PRIVATE(chosen_method));
152
+ }
153
+
154
+ void Edhoc::SetCipherSuites(const Napi::CallbackInfo& info, const Napi::Value& value) {
155
+ Napi::Env env = info.Env();
156
+
157
+ if (!value.IsArray()) {
158
+ Napi::TypeError::New(env, kErrorArraySuiteIndexesExpected)
159
+ .ThrowAsJavaScriptException();
160
+ }
161
+
162
+ const auto jsArray = value.As<Napi::Array>();
163
+ std::vector<edhoc_cipher_suite> selected_suites;
164
+ selected_suites.reserve(jsArray.Length());
165
+
166
+ for (uint32_t i = 0; i < jsArray.Length(); i++) {
167
+ const uint32_t index = jsArray.Get(i).As<Napi::Number>().Uint32Value();
168
+
169
+ if (index >= suite_pointers_count || suite_pointers[index] == nullptr) {
170
+ Napi::RangeError::New(env, kErrorInvalidCipherSuiteIndex)
171
+ .ThrowAsJavaScriptException();
172
+ }
173
+
174
+ selected_suites.push_back(*suite_pointers[index]);
175
+ }
176
+
177
+ if (edhoc_set_cipher_suites(edhocContext_.get(), selected_suites.data(), selected_suites.size()) != 0) {
178
+ Napi::TypeError::New(env, kErrorFailedToSetCipherSuites)
179
+ .ThrowAsJavaScriptException();
180
+ }
181
+ }
182
+
183
+ Napi::Value Edhoc::GetCipherSuites(const Napi::CallbackInfo& info) {
184
+ Napi::Env env = info.Env();
185
+ Napi::Array result = Napi::Array::New(env, edhocContext_->EDHOC_PRIVATE(csuite_len));
186
+ for (size_t i = 0; i < edhocContext_->EDHOC_PRIVATE(csuite_len); i++) {
187
+ result.Set(i, Napi::Number::New(env, edhocContext_->EDHOC_PRIVATE(csuite)[i].value));
188
+ }
189
+ return result;
190
+ }
191
+
192
+ Napi::Value Edhoc::GetSelectedCipherSuite(const Napi::CallbackInfo& info) {
193
+ Napi::Env env = info.Env();
194
+ Napi::Number suite =
195
+ Napi::Number::New(env, edhocContext_->EDHOC_PRIVATE(csuite)[edhocContext_->EDHOC_PRIVATE(chosen_csuite_idx)].value);
196
+ return suite;
197
+ }
198
+
199
+ Napi::Value Edhoc::GetLogger(const Napi::CallbackInfo& info) {
200
+ return logger_.Value();
201
+ }
202
+
203
+ void Edhoc::SetLogger(const Napi::CallbackInfo& info, const Napi::Value& value) {
204
+ if (!info[0].IsFunction()) {
205
+ Napi::TypeError::New(info.Env(), kErrorExpectedAFunction).ThrowAsJavaScriptException();
206
+ }
207
+ Napi::Function jsCallback = info[0].As<Napi::Function>();
208
+ logger_ = Napi::Persistent(jsCallback);
209
+ }
210
+
211
+ void Edhoc::Logger(void* user_context, const char* name, const uint8_t* buffer, size_t buffer_length) {
212
+ RunningContext* context = static_cast<RunningContext*>(const_cast<void*>(user_context));
213
+
214
+ if (!context || !context->GetTsfn() || !context->GetLoggerRef()) {
215
+ return;
216
+ }
217
+
218
+ const std::vector<uint8_t> bufferCopy(buffer, buffer + buffer_length);
219
+
220
+ context->GetTsfn().NonBlockingCall(context, [name = std::string(name), bufferCopy](Napi::Env env, Napi::Function jsCallback, RunningContext* context) {
221
+ Napi::HandleScope scope(env);
222
+ try {
223
+ context->GetLoggerRef().Value().As<Napi::Function>().Call({Napi::String::New(env, name), Napi::Buffer<uint8_t>::Copy(env, bufferCopy.data(), bufferCopy.size())});
224
+ } catch (const Napi::Error& e) {
225
+ // This is just a logger, so we don't want to throw an error
226
+ std::cerr << "Error in Logger: " << e.Get("stack").ToString().Utf8Value() << std::endl;
227
+ }
228
+ });
229
+ }
230
+
231
+ void Edhoc::StartRunningContext(Napi::Env env) {
232
+ // Initialize the running context
233
+ this->runningContext_ = std::make_unique<RunningContext>(
234
+ env,
235
+ edhocContext_.get(),
236
+ this->cryptoManager_.get(),
237
+ this->eadManager_.get(),
238
+ this->credentialManager_.get(),
239
+ logger_.Value()
240
+ );
241
+
242
+ // Set the user context of the EDHOC context
243
+ if (edhoc_set_user_context(edhocContext_.get(), static_cast<void*>(this->runningContext_.get())) != EDHOC_SUCCESS) {
244
+ Napi::TypeError::New(env, kErrorFailedToInitializeEdhocContext)
245
+ .ThrowAsJavaScriptException();
246
+ }
247
+ }
248
+
249
+ Napi::Value Edhoc::ComposeMessage(const Napi::CallbackInfo& info, enum edhoc_message messageNumber) {
250
+ Napi::Env env = info.Env();
251
+ Napi::HandleScope scope(env);
252
+
253
+ // Check if the first argument (EADs) is an array
254
+ if (info[0].IsArray()) {
255
+ try {
256
+ this->eadManager_->StoreEad(messageNumber, info[0].As<Napi::Array>());
257
+ } catch (const Napi::Error& e) {
258
+ e.ThrowAsJavaScriptException();
259
+ return env.Null();
260
+ }
261
+ }
262
+
263
+ // Start the running context
264
+ this->StartRunningContext(env);
265
+
266
+ // Compose the message
267
+ EdhocComposeAsyncWorker* worker = new EdhocComposeAsyncWorker(this->runningContext_.get(), messageNumber);
268
+ worker->Queue();
269
+
270
+ // Return the promise of the running context
271
+ return this->runningContext_->GetPromise();
272
+ }
273
+
274
+ Napi::Value Edhoc::ProcessMessage(const Napi::CallbackInfo& info, enum edhoc_message messageNumber) {
275
+ Napi::Env env = info.Env();
276
+ Napi::HandleScope scope(env);
277
+
278
+ // Check if the first argument (input buffer) is a buffer
279
+ if (info.Length() < 1 || !info[0].IsBuffer()) {
280
+ Napi::TypeError::New(env, kErrorExpectedFirstArgumentToBeBuffer).ThrowAsJavaScriptException();
281
+ return env.Null();
282
+ }
283
+
284
+ // Get the input buffer
285
+ Napi::Buffer<uint8_t> inputBuffer = info[0].As<Napi::Buffer<uint8_t>>();
286
+
287
+ // Start the running context
288
+ this->StartRunningContext(env);
289
+
290
+ // Process the message
291
+ EdhocProcessAsyncWorker* worker = new EdhocProcessAsyncWorker(this->runningContext_.get(), messageNumber, inputBuffer);
292
+ worker->Queue();
293
+
294
+ // Return the promise of the running context
295
+ return this->runningContext_->GetPromise();
296
+ }
297
+
298
+ Napi::Value Edhoc::ComposeMessage1(const Napi::CallbackInfo& info) {
299
+ return ComposeMessage(info, EDHOC_MSG_1);
300
+ }
301
+
302
+ Napi::Value Edhoc::ProcessMessage1(const Napi::CallbackInfo& info) {
303
+ return ProcessMessage(info, EDHOC_MSG_1);
304
+ }
305
+
306
+ Napi::Value Edhoc::ComposeMessage2(const Napi::CallbackInfo& info) {
307
+ return ComposeMessage(info, EDHOC_MSG_2);
308
+ }
309
+
310
+ Napi::Value Edhoc::ProcessMessage2(const Napi::CallbackInfo& info) {
311
+ return ProcessMessage(info, EDHOC_MSG_2);
312
+ }
313
+
314
+ Napi::Value Edhoc::ComposeMessage3(const Napi::CallbackInfo& info) {
315
+ return ComposeMessage(info, EDHOC_MSG_3);
316
+ }
317
+
318
+ Napi::Value Edhoc::ProcessMessage3(const Napi::CallbackInfo& info) {
319
+ return ProcessMessage(info, EDHOC_MSG_3);
320
+ }
321
+
322
+ Napi::Value Edhoc::ComposeMessage4(const Napi::CallbackInfo& info) {
323
+ return ComposeMessage(info, EDHOC_MSG_4);
324
+ }
325
+
326
+ Napi::Value Edhoc::ProcessMessage4(const Napi::CallbackInfo& info) {
327
+ return ProcessMessage(info, EDHOC_MSG_4);
328
+ }
329
+
330
+ Napi::Value Edhoc::ExportOSCORE(const Napi::CallbackInfo& info) {
331
+ Napi::Env env = info.Env();
332
+ Napi::HandleScope scope(env);
333
+
334
+ // Start the running context
335
+ this->StartRunningContext(env);
336
+
337
+ // Export the OSCORE
338
+ EdhocExportOscoreAsyncWorker* worker = new EdhocExportOscoreAsyncWorker(this->runningContext_.get());
339
+ worker->Queue();
340
+
341
+ // Return the promise of the running context
342
+ return this->runningContext_->GetPromise();
343
+ }
344
+
345
+ Napi::Value Edhoc::ExportKey(const Napi::CallbackInfo& info) {
346
+ Napi::Env env = info.Env();
347
+ Napi::HandleScope scope(env);
348
+
349
+ // Check if the first argument (label) is a number
350
+ if (info.Length() < 1 || !info[0].IsNumber()) {
351
+ Napi::TypeError::New(env, kErrorExpectedArgumentToBeNumber).ThrowAsJavaScriptException();
352
+ return env.Null();
353
+ }
354
+
355
+ // Check if the second argument (desired length) is a number
356
+ if (info.Length() < 2 || !info[1].IsNumber()) {
357
+ Napi::TypeError::New(env, kErrorExpectedArgumentToBeNumber).ThrowAsJavaScriptException();
358
+ return env.Null();
359
+ }
360
+
361
+ // Get the label and desired length
362
+ uint16_t label = (uint16_t)info[0].As<Napi::Number>().Uint32Value();
363
+ uint8_t desiredLength = (uint8_t)info[1].As<Napi::Number>().Uint32Value();
364
+
365
+ // Start the running context
366
+ this->StartRunningContext(env);
367
+
368
+ // Export the key
369
+ EdhocKeyExporterAsyncWorker* worker = new EdhocKeyExporterAsyncWorker(this->runningContext_.get(), label, desiredLength);
370
+ worker->Queue();
371
+
372
+ // Return the promise of the running context
373
+ return this->runningContext_->GetPromise();
374
+ }
375
+
376
+ Napi::Value Edhoc::KeyUpdate(const Napi::CallbackInfo& info) {
377
+ Napi::Env env = info.Env();
378
+ Napi::HandleScope scope(env);
379
+
380
+ // Check if the first argument (context buffer) is a buffer
381
+ if (info.Length() < 1 || !info[0].IsBuffer()) {
382
+ Napi::TypeError::New(env, kErrorExpectedFirstArgumentToBeBuffer).ThrowAsJavaScriptException();
383
+ return env.Null();
384
+ }
385
+
386
+ // Get the context buffer
387
+ Napi::Buffer<uint8_t> contextBuffer = info[0].As<Napi::Buffer<uint8_t>>();
388
+ std::vector<uint8_t> contextBufferVector(contextBuffer.Data(), contextBuffer.Data() + contextBuffer.Length());
389
+
390
+ // Start the running context
391
+ this->StartRunningContext(env);
392
+
393
+ // Update the key
394
+ EdhocKeyUpdateAsyncWorker* worker = new EdhocKeyUpdateAsyncWorker(this->runningContext_.get(), contextBufferVector);
395
+ worker->Queue();
396
+
397
+ // Return the promise of the running context
398
+ return this->runningContext_->GetPromise();
399
+ }
400
+
401
+ Napi::Object Edhoc::Init(Napi::Env env, Napi::Object exports) {
402
+ Napi::HandleScope scope(env);
403
+
404
+ Napi::Function func = DefineClass(env, "EDHOC", {
405
+ InstanceAccessor("connectionID", &Edhoc::GetCID, &Edhoc::SetCID),
406
+ InstanceAccessor<&Edhoc::GetPeerCID>("peerConnectionID"),
407
+ InstanceAccessor("methods", &Edhoc::GetMethods, &Edhoc::SetMethods),
408
+ InstanceAccessor<&Edhoc::GetSelectedMethod>("selectedMethod"),
409
+ InstanceAccessor("cipherSuites", &Edhoc::GetCipherSuites, &Edhoc::SetCipherSuites),
410
+ InstanceAccessor<&Edhoc::GetSelectedCipherSuite>("selectedSuite"),
411
+ InstanceAccessor("logger", &Edhoc::GetLogger, &Edhoc::SetLogger),
412
+ InstanceMethod("reset", &Edhoc::Reset),
413
+ InstanceMethod("composeMessage1", &Edhoc::ComposeMessage1),
414
+ InstanceMethod("processMessage1", &Edhoc::ProcessMessage1),
415
+ InstanceMethod("composeMessage2", &Edhoc::ComposeMessage2),
416
+ InstanceMethod("processMessage2", &Edhoc::ProcessMessage2),
417
+ InstanceMethod("composeMessage3", &Edhoc::ComposeMessage3),
418
+ InstanceMethod("processMessage3", &Edhoc::ProcessMessage3),
419
+ InstanceMethod("composeMessage4", &Edhoc::ComposeMessage4),
420
+ InstanceMethod("processMessage4", &Edhoc::ProcessMessage4),
421
+ InstanceMethod("exportOSCORE", &Edhoc::ExportOSCORE),
422
+ InstanceMethod("exportKey", &Edhoc::ExportKey),
423
+ InstanceMethod("keyUpdate", &Edhoc::KeyUpdate),
424
+ });
425
+
426
+ Napi::FunctionReference* constructor = new Napi::FunctionReference();
427
+ *constructor = Napi::Persistent(func);
428
+ env.SetInstanceData(constructor);
429
+
430
+ exports.Set("EDHOC", func);
431
+ return exports;
432
+ }
433
+
434
+ NODE_API_NAMED_ADDON(addon, Edhoc);
@@ -5,74 +5,56 @@ static constexpr const char* kErrorInvalidMessageNumber = "Invalid message numbe
5
5
  static constexpr const char* kErrorMessageFormat = "Failed to compose EDHOC message %d. Error code: %d";
6
6
  static constexpr size_t kErrorBufferSize = 100;
7
7
 
8
- EdhocComposeAsyncWorker::EdhocComposeAsyncWorker(Napi::Env& env,
9
- struct edhoc_context& context,
10
- int messageNumber,
11
- CallbackType callback)
12
- : Napi::AsyncWorker(env),
13
- deferred(Napi::Promise::Deferred::New(env)),
14
- context(context),
15
- messageNumber(messageNumber),
16
- callback(std::move(callback)) {}
8
+ EdhocComposeAsyncWorker::EdhocComposeAsyncWorker(RunningContext* runningContext, int messageNumber)
9
+ : Napi::AsyncWorker(runningContext->GetEnv()),
10
+ runningContext_(runningContext),
11
+ messageNumber_(messageNumber) {}
17
12
 
18
13
  void EdhocComposeAsyncWorker::Execute() {
19
- composedMessage.resize(kInitialBufferSize);
20
- size_t composedMessageLength = 0;
21
-
22
- int ret = EDHOC_ERROR_GENERIC_ERROR;
23
- switch (messageNumber) {
24
- case EDHOC_MSG_1:
25
- ret = edhoc_message_1_compose(&context, composedMessage.data(), composedMessage.size(), &composedMessageLength);
26
- break;
27
- case EDHOC_MSG_2:
28
- ret = edhoc_message_2_compose(&context, composedMessage.data(), composedMessage.size(), &composedMessageLength);
29
- break;
30
- case EDHOC_MSG_3:
31
- ret = edhoc_message_3_compose(&context, composedMessage.data(), composedMessage.size(), &composedMessageLength);
32
- break;
33
- case EDHOC_MSG_4:
34
- ret = edhoc_message_4_compose(&context, composedMessage.data(), composedMessage.size(), &composedMessageLength);
35
- break;
36
- default:
37
- SetError(kErrorInvalidMessageNumber);
38
- return;
39
- }
40
-
41
- composedMessage.resize(composedMessageLength);
42
-
43
- if (ret != EDHOC_SUCCESS) {
44
- char errorMessage[kErrorBufferSize];
45
- std::snprintf(errorMessage, kErrorBufferSize, kErrorMessageFormat, messageNumber + 1, ret);
46
- SetError(errorMessage);
14
+ try {
15
+ composedMessage_.resize(kInitialBufferSize);
16
+ size_t composedMessageLength = 0;
17
+
18
+ int ret = EDHOC_ERROR_GENERIC_ERROR;
19
+ switch (messageNumber_) {
20
+ case EDHOC_MSG_1:
21
+ ret = edhoc_message_1_compose(runningContext_->GetEdhocContext(), composedMessage_.data(), composedMessage_.size(), &composedMessageLength);
22
+ break;
23
+ case EDHOC_MSG_2:
24
+ ret = edhoc_message_2_compose(runningContext_->GetEdhocContext(), composedMessage_.data(), composedMessage_.size(), &composedMessageLength);
25
+ break;
26
+ case EDHOC_MSG_3:
27
+ ret = edhoc_message_3_compose(runningContext_->GetEdhocContext(), composedMessage_.data(), composedMessage_.size(), &composedMessageLength);
28
+ break;
29
+ case EDHOC_MSG_4:
30
+ ret = edhoc_message_4_compose(runningContext_->GetEdhocContext(), composedMessage_.data(), composedMessage_.size(), &composedMessageLength);
31
+ break;
32
+ default:
33
+ SetError(kErrorInvalidMessageNumber);
34
+ return;
35
+ }
36
+
37
+ composedMessage_.resize(composedMessageLength);
38
+
39
+ if (ret != EDHOC_SUCCESS) {
40
+ char errorMessage[kErrorBufferSize];
41
+ std::snprintf(errorMessage, kErrorBufferSize, kErrorMessageFormat, messageNumber_ + 1, ret);
42
+ SetError(errorMessage);
43
+ }
44
+ } catch (const std::exception& e) {
45
+ SetError(e.what());
47
46
  }
48
47
  }
49
48
 
50
49
  void EdhocComposeAsyncWorker::OnOK() {
51
50
  Napi::Env env = Env();
52
51
  Napi::HandleScope scope(env);
53
-
54
- callback(env);
55
-
56
- if (env.IsExceptionPending()) {
57
- deferred.Reject(env.GetAndClearPendingException().Value());
58
- } else {
59
- deferred.Resolve(Napi::Buffer<uint8_t>::Copy(env, composedMessage.data(), composedMessage.size()));
60
- }
52
+ runningContext_->Resolve(Napi::Buffer<uint8_t>::Copy(env, composedMessage_.data(), composedMessage_.size()));
53
+ runningContext_->GetEadManager()->ClearEadByMessage(static_cast<enum edhoc_message>(messageNumber_));
61
54
  }
62
55
 
63
56
  void EdhocComposeAsyncWorker::OnError(const Napi::Error& error) {
64
57
  Napi::Env env = Env();
65
58
  Napi::HandleScope scope(env);
66
-
67
- callback(env);
68
-
69
- if (env.IsExceptionPending()) {
70
- deferred.Reject(env.GetAndClearPendingException().Value());
71
- } else {
72
- deferred.Reject(error.Value());
73
- }
74
- }
75
-
76
- Napi::Promise EdhocComposeAsyncWorker::GetPromise() {
77
- return deferred.Promise();
59
+ runningContext_->Reject(error.Value());
78
60
  }