asherah 1.3.18 → 1.3.20

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "asherah",
3
- "version": "1.3.18",
3
+ "version": "1.3.20",
4
4
  "description": "Asherah envelope encryption and key rotation library",
5
5
  "exports": {
6
6
  "node-addons": "./dist/asherah.node"
@@ -4,8 +4,8 @@ echo "Downloading Asherah libraries"
4
4
 
5
5
  source .asherah-version
6
6
 
7
- rm -rf lib
8
- mkdir lib
7
+ #rm -rf lib
8
+ mkdir -p lib
9
9
  cd lib || exit 1
10
10
 
11
11
  OS=$(uname)
@@ -51,5 +51,5 @@ curl -s -L --fail -O --retry 999 --retry-max-time 0 "https://github.com/godaddy/
51
51
  grep -e "${ARCHIVE}" -e "${HEADER}" "${SUMS}" > ./SHA256SUM
52
52
  #shasum -a 256 -c ./SHA256SUM || (echo 'SHA256 mismatch!' ; rm -f ./*.a ./*.h ; exit 1)
53
53
 
54
- mv "${ARCHIVE}" libasherah.a
55
- mv "${HEADER}" libasherah.h
54
+ mv -f "${ARCHIVE}" libasherah.a
55
+ mv -f "${HEADER}" libasherah.h
package/src/asherah.cc CHANGED
@@ -17,12 +17,10 @@ void setup(const Napi::CallbackInfo &info) {
17
17
 
18
18
  if (unlikely(setup_state == 1)) {
19
19
  log_error_and_throw(env, "setup", "setup called twice");
20
- return;
21
20
  }
22
21
 
23
22
  if (unlikely(info.Length() < 1)) {
24
23
  log_error_and_throw(env, "setup", "Wrong number of arguments");
25
- return;
26
24
  }
27
25
 
28
26
  Napi::String config;
@@ -38,13 +36,12 @@ void setup(const Napi::CallbackInfo &info) {
38
36
  config_json = parse.Call(json, {config}).As<Napi::Object>();
39
37
  } else {
40
38
  log_error_and_throw(env, "setup", "Wrong argument type");
41
- return;
42
39
  }
43
40
 
44
41
  Napi::String product_id = config_json.Get("ProductID").As<Napi::String>();
45
42
  Napi::String service_name = config_json.Get("ServiceName").As<Napi::String>();
46
43
 
47
- est_intermediate_key_overhead =
44
+ *est_intermediate_key_overhead_ptr =
48
45
  product_id.Utf8Value().length() + service_name.Utf8Value().length();
49
46
 
50
47
  Napi::Value verbose = config_json.Get("Verbose");
@@ -56,49 +53,15 @@ void setup(const Napi::CallbackInfo &info) {
56
53
  debug_log("setup", "verbose_flag: defaulting to false");
57
54
  }
58
55
 
59
- // Determine size
60
- size_t config_utf8_byte_length;
61
- config_utf8_byte_length = nstring_utf8_byte_length(env, config);
62
- if (unlikely(config_utf8_byte_length == (size_t)(-1))) {
63
- log_error_and_throw(env, "setup", "Failed to get config utf8 length");
64
- return;
65
- }
66
-
67
- // Allocate
68
56
  char *config_cobhan_buffer;
69
- std::unique_ptr<char[]> config_cobhan_buffer_unique_ptr;
70
- if (config_utf8_byte_length < max_stack_alloc_size) {
71
- // If the buffer is small enough, allocate it on the stack
72
- size_t config_cobhan_buffer_size_bytes =
73
- calculate_cobhan_buffer_size_bytes(config_utf8_byte_length);
74
- debug_log_alloca("setup", "config_cobhan_buffer",
75
- config_cobhan_buffer_size_bytes);
76
- config_cobhan_buffer = (char *)alloca(config_cobhan_buffer_size_bytes);
77
- configure_cbuffer(config_cobhan_buffer, config_utf8_byte_length);
78
- } else {
79
- // Otherwise, allocate it on the heap
80
- config_cobhan_buffer_unique_ptr =
81
- heap_allocate_cbuffer("config_cobhan_buffer", config_utf8_byte_length);
82
- config_cobhan_buffer = config_cobhan_buffer_unique_ptr.get();
83
- }
84
- if (unlikely(config_cobhan_buffer == nullptr)) {
85
- log_error_and_throw(env, "setup",
86
- "Failed to allocate config cobhan buffer");
87
- return;
88
- }
57
+ size_t config_copied_bytes = 0;
58
+ NAPI_STRING_TO_CBUFFER(config, config_cobhan_buffer, config_copied_bytes,
59
+ "setup");
89
60
 
90
- // Copy
91
- size_t config_copied_bytes;
92
- config_cobhan_buffer =
93
- copy_nstring_to_cbuffer(env, config, config_utf8_byte_length,
94
- config_cobhan_buffer, &config_copied_bytes);
95
- if (unlikely(config_cobhan_buffer == nullptr)) {
96
- log_error_and_throw(env, "setup", "Failed to copy config to cobhan buffer");
97
- return;
98
- }
99
-
100
- if (unlikely(verbose_flag)) {
101
- debug_log("setup", "Calling asherah-cobhan SetupJson");
61
+ char *config_canary_ptr = get_canary_ptr(config_cobhan_buffer);
62
+ if (unlikely(!check_canary_ptr(config_canary_ptr))) {
63
+ log_error_and_throw(env, "encrypt_to_json",
64
+ "Failed initial canary check for config_cobhan_buffer");
102
65
  }
103
66
 
104
67
  // extern GoInt32 SetupJson(void* configJson);
@@ -108,17 +71,23 @@ void setup(const Napi::CallbackInfo &info) {
108
71
  debug_log("setup", "Returned from asherah-cobhan SetupJson");
109
72
  }
110
73
 
74
+ if (unlikely(!check_canary_ptr(config_canary_ptr))) {
75
+ log_error_and_throw(
76
+ env, "encrypt_to_json",
77
+ "Failed post-call canary check for config_cobhan_buffer");
78
+ }
79
+
111
80
  if (unlikely(result < 0)) {
112
81
  // TODO: Convert this to a proper error message
113
82
  log_error_and_throw(env, "setup", std::to_string(result));
114
- return;
115
83
  }
116
84
  setup_state = 1;
117
85
  }
118
86
 
119
- Napi::Value encrypt_to_json(Napi::Env &env, size_t partition_bytes,
120
- size_t data_bytes, char *partition_id_cobhan_buffer,
121
- char *input_cobhan_buffer) {
87
+ Napi::String encrypt_to_json(Napi::Env &env, size_t partition_bytes,
88
+ size_t data_bytes,
89
+ char *partition_id_cobhan_buffer,
90
+ char *input_cobhan_buffer) {
122
91
 
123
92
  size_t asherah_output_size_bytes =
124
93
  estimate_asherah_output_size_bytes(data_bytes, partition_bytes);
@@ -129,24 +98,24 @@ Napi::Value encrypt_to_json(Napi::Env &env, size_t partition_bytes,
129
98
  }
130
99
 
131
100
  char *output_cobhan_buffer;
132
- std::unique_ptr<char[]> output_cobhan_buffer_unique_ptr;
133
- if (asherah_output_size_bytes < max_stack_alloc_size) {
134
- // If the buffer is small enough, allocate it on the stack
135
- size_t output_cobhan_buffer_size_bytes =
136
- calculate_cobhan_buffer_size_bytes(asherah_output_size_bytes);
137
- debug_log_alloca("encrypt_to_json", "output_cobhan_buffer",
138
- output_cobhan_buffer_size_bytes);
139
- output_cobhan_buffer = (char *)alloca(output_cobhan_buffer_size_bytes);
140
- configure_cbuffer(output_cobhan_buffer, asherah_output_size_bytes);
141
- } else {
142
- // Otherwise, allocate it on the heap
143
- output_cobhan_buffer_unique_ptr = heap_allocate_cbuffer(
144
- "output_cobhan_buffer", asherah_output_size_bytes);
145
- output_cobhan_buffer = output_cobhan_buffer_unique_ptr.get();
101
+ ALLOCATE_OUTPUT_CBUFFER(output_cobhan_buffer, asherah_output_size_bytes,
102
+ "encrypt_to_json");
103
+
104
+ char *partition_id_canary_ptr = get_canary_ptr(partition_id_cobhan_buffer);
105
+ if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
106
+ log_error_and_throw(
107
+ env, "encrypt_to_json",
108
+ "Failed initial canary check for partition_id_cobhan_buffer");
109
+ }
110
+ char *input_canary_ptr = get_canary_ptr(input_cobhan_buffer);
111
+ if (unlikely(!check_canary_ptr(input_canary_ptr))) {
112
+ log_error_and_throw(env, "encrypt_to_json",
113
+ "Failed initial canary check for input_cobhan_buffer");
146
114
  }
147
- if (unlikely(output_cobhan_buffer == nullptr)) {
148
- return log_error_and_throw(env, "encrypt_to_json",
149
- "Failed to allocate cobhan output buffer");
115
+ char *output_canary_ptr = get_canary_ptr(output_cobhan_buffer);
116
+ if (unlikely(!check_canary_ptr(output_canary_ptr))) {
117
+ log_error_and_throw(env, "encrypt_to_json",
118
+ "Failed initial canary check for output_cobhan_buffer");
150
119
  }
151
120
 
152
121
  if (unlikely(verbose_flag)) {
@@ -162,16 +131,32 @@ Napi::Value encrypt_to_json(Napi::Env &env, size_t partition_bytes,
162
131
  debug_log("encrypt_to_json", "Returning from asherah-cobhan EncryptToJson");
163
132
  }
164
133
 
134
+ if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
135
+ log_error_and_throw(
136
+ env, "encrypt_to_json",
137
+ "Failed post-call canary check for partition_id_cobhan_buffer");
138
+ }
139
+ if (unlikely(!check_canary_ptr(input_canary_ptr))) {
140
+ log_error_and_throw(
141
+ env, "encrypt_to_json",
142
+ "Failed post-call canary check for input_cobhan_buffer");
143
+ }
144
+ if (unlikely(!check_canary_ptr(output_canary_ptr))) {
145
+ log_error_and_throw(
146
+ env, "encrypt_to_json",
147
+ "Failed post-call canary check for output_cobhan_buffer");
148
+ }
149
+
165
150
  if (unlikely(result < 0)) {
166
151
  // TODO: Convert this to a proper error message
167
- return log_error_and_throw(env, "encrypt_to_json", std::to_string(result));
152
+ log_error_and_throw(env, "encrypt_to_json", std::to_string(result));
168
153
  }
169
154
 
170
- Napi::Value output = cbuffer_to_nstring(env, output_cobhan_buffer);
155
+ Napi::String output = cbuffer_to_nstring(env, output_cobhan_buffer);
171
156
  return output;
172
157
  }
173
158
 
174
- Napi::Value encrypt(const Napi::CallbackInfo &info) {
159
+ Napi::String encrypt(const Napi::CallbackInfo &info) {
175
160
  Napi::Env env = info.Env();
176
161
 
177
162
  if (unlikely(verbose_flag)) {
@@ -179,102 +164,32 @@ Napi::Value encrypt(const Napi::CallbackInfo &info) {
179
164
  }
180
165
 
181
166
  if (unlikely(setup_state == 0)) {
182
- return log_error_and_throw(env, "encrypt", "setup() not called");
167
+ log_error_and_throw(env, "encrypt", "setup() not called");
183
168
  }
184
169
 
185
170
  if (unlikely(info.Length() < 2)) {
186
- return log_error_and_throw(env, "encrypt", "Wrong number of arguments");
171
+ log_error_and_throw(env, "encrypt", "Wrong number of arguments");
187
172
  }
188
173
 
189
174
  if (unlikely(!info[0].IsString() || !info[1].IsBuffer())) {
190
- return log_error_and_throw(env, "encrypt", "Wrong argument types");
175
+ log_error_and_throw(env, "encrypt", "Wrong argument types");
191
176
  }
192
177
 
193
- // Determine size
194
- size_t partition_utf8_byte_length;
195
178
  Napi::String partition_id = info[0].As<Napi::String>();
196
- partition_utf8_byte_length = nstring_utf8_byte_length(env, partition_id);
197
- if (unlikely(partition_utf8_byte_length == (size_t)(-1))) {
198
- return log_error_and_throw(env, "encrypt",
199
- "Failed to get partition_id utf8 length");
200
- }
201
- if (unlikely(partition_utf8_byte_length == 0)) {
202
- return log_error_and_throw(env, "encrypt", "partition_id is empty");
203
- }
204
-
205
- // Allocate
206
179
  char *partition_id_cobhan_buffer;
207
- std::unique_ptr<char[]> partition_id_cobhan_buffer_unique_ptr;
208
- if (partition_utf8_byte_length < max_stack_alloc_size) {
209
- // If the buffer is small enough, allocate it on the stack
210
- size_t partition_id_cobhan_buffer_size_bytes =
211
- calculate_cobhan_buffer_size_bytes(partition_utf8_byte_length);
212
- debug_log_alloca("encrypt", "partition_id_cobhan_buffer",
213
- partition_id_cobhan_buffer_size_bytes);
214
- partition_id_cobhan_buffer =
215
- (char *)alloca(partition_id_cobhan_buffer_size_bytes);
216
- configure_cbuffer(partition_id_cobhan_buffer, partition_utf8_byte_length);
217
- } else {
218
- // Otherwise, allocate it on the heap
219
- partition_id_cobhan_buffer_unique_ptr = heap_allocate_cbuffer(
220
- "partition_id_cobhan_buffer", partition_utf8_byte_length);
221
- partition_id_cobhan_buffer = partition_id_cobhan_buffer_unique_ptr.get();
222
- }
223
- if (unlikely(partition_id_cobhan_buffer == nullptr)) {
224
- return log_error_and_throw(env, "encrypt",
225
- "Failed to allocate partitionId cobhan buffer");
226
- }
227
-
228
- // Copy
229
- size_t partition_copied_bytes;
230
- partition_id_cobhan_buffer = copy_nstring_to_cbuffer(
231
- env, partition_id, partition_utf8_byte_length, partition_id_cobhan_buffer,
232
- &partition_copied_bytes);
233
- if (unlikely(partition_id_cobhan_buffer == nullptr)) {
234
- return log_error_and_throw(env, "encrypt",
235
- "Failed to copy partitionId to cobhan buffer");
236
- }
180
+ size_t partition_id_copied_bytes = 0;
181
+ NAPI_STRING_TO_CBUFFER(partition_id, partition_id_cobhan_buffer,
182
+ partition_id_copied_bytes, "encrypt");
237
183
 
238
- // Determine size
239
184
  Napi::Buffer<unsigned char> input_napi_buffer =
240
185
  info[1].As<Napi::Buffer<unsigned char>>();
241
- size_t input_byte_length = input_napi_buffer.ByteLength();
242
- if (unlikely(input_byte_length == 0)) {
243
- return log_error_and_throw(env, "encrypt", "input is empty");
244
- }
245
-
246
- // Allocate
247
186
  char *input_cobhan_buffer;
248
- std::unique_ptr<char[]> input_buffer_unique_ptr;
249
- if (input_byte_length < max_stack_alloc_size) {
250
- // If the buffer is small enough, allocate it on the stack
251
- size_t input_cobhan_buffer_size_bytes =
252
- calculate_cobhan_buffer_size_bytes(input_byte_length);
253
- debug_log_alloca("encrypt", "input_cobhan_buffer",
254
- input_cobhan_buffer_size_bytes);
255
- input_cobhan_buffer = (char *)alloca(input_cobhan_buffer_size_bytes);
256
- configure_cbuffer(input_cobhan_buffer, input_byte_length);
257
- } else {
258
- // Otherwise, allocate it on the heap
259
- input_buffer_unique_ptr =
260
- heap_allocate_cbuffer("input_cobhan_buffer", input_byte_length);
261
- input_cobhan_buffer = input_buffer_unique_ptr.get();
262
- }
263
- if (unlikely(input_cobhan_buffer == nullptr)) {
264
- return log_error_and_throw(
265
- env, "encrypt", "Failed to allocate cobhan buffer for input buffer");
266
- }
267
-
268
- // Copy
269
- input_cobhan_buffer =
270
- copy_nbuffer_to_cbuffer(env, input_napi_buffer, input_cobhan_buffer);
271
- if (unlikely(input_cobhan_buffer == nullptr)) {
272
- return log_error_and_throw(env, "encrypt",
273
- "Failed to copy input buffer to cobhan buffer");
274
- }
187
+ size_t input_copied_bytes = 0;
188
+ NAPI_BUFFER_TO_CBUFFER(input_napi_buffer, input_cobhan_buffer,
189
+ input_copied_bytes, "encrypt");
275
190
 
276
- Napi::Value output =
277
- encrypt_to_json(env, partition_copied_bytes, input_byte_length,
191
+ Napi::String output =
192
+ encrypt_to_json(env, partition_id_copied_bytes, input_copied_bytes,
278
193
  partition_id_cobhan_buffer, input_cobhan_buffer);
279
194
 
280
195
  if (unlikely(verbose_flag)) {
@@ -284,7 +199,7 @@ Napi::Value encrypt(const Napi::CallbackInfo &info) {
284
199
  return output;
285
200
  }
286
201
 
287
- Napi::Value encrypt_string(const Napi::CallbackInfo &info) {
202
+ Napi::String encrypt_string(const Napi::CallbackInfo &info) {
288
203
  Napi::Env env = info.Env();
289
204
 
290
205
  if (unlikely(verbose_flag)) {
@@ -292,109 +207,31 @@ Napi::Value encrypt_string(const Napi::CallbackInfo &info) {
292
207
  }
293
208
 
294
209
  if (unlikely(setup_state == 0)) {
295
- return log_error_and_throw(env, "encrypt_string", "setup() not called");
210
+ log_error_and_throw(env, "encrypt_string", "setup() not called");
296
211
  }
297
212
 
298
213
  if (unlikely(info.Length() < 2)) {
299
- return log_error_and_throw(env, "encrypt_string",
300
- "Wrong number of arguments");
214
+ log_error_and_throw(env, "encrypt_string", "Wrong number of arguments");
301
215
  }
302
216
 
303
217
  if (unlikely(!info[0].IsString() || !info[1].IsString())) {
304
- return log_error_and_throw(env, "encrypt_string", "Wrong argument types");
218
+ log_error_and_throw(env, "encrypt_string", "Wrong argument types");
305
219
  }
306
220
 
307
- // Determine size
308
- size_t partition_utf8_byte_length;
309
221
  Napi::String partition_id = info[0].As<Napi::String>();
310
- partition_utf8_byte_length = nstring_utf8_byte_length(env, partition_id);
311
- if (unlikely(partition_utf8_byte_length == (size_t)(-1))) {
312
- return log_error_and_throw(env, "encrypt_string",
313
- "Failed to get partition_id utf8 length");
314
- }
315
- if (unlikely(partition_utf8_byte_length == 0)) {
316
- return log_error_and_throw(env, "encrypt_string", "partition_id is empty");
317
- }
318
-
319
- // Allocate
320
222
  char *partition_id_cobhan_buffer;
321
- std::unique_ptr<char[]> partition_id_cobhan_buffer_unique_ptr;
322
- if (partition_utf8_byte_length < max_stack_alloc_size) {
323
- // If the buffer is small enough, allocate it on the stack
324
- size_t partition_id_cobhan_buffer_size_bytes =
325
- calculate_cobhan_buffer_size_bytes(partition_utf8_byte_length);
326
- debug_log_alloca("encrypt_string", "partition_id_cobhan_buffer",
327
- partition_id_cobhan_buffer_size_bytes);
328
- partition_id_cobhan_buffer =
329
- (char *)alloca(partition_id_cobhan_buffer_size_bytes);
330
- configure_cbuffer(partition_id_cobhan_buffer, partition_utf8_byte_length);
331
- } else {
332
- // Otherwise, allocate it on the heap
333
- partition_id_cobhan_buffer_unique_ptr = heap_allocate_cbuffer(
334
- "partition_id_cobhan_buffer", partition_utf8_byte_length);
335
- partition_id_cobhan_buffer = partition_id_cobhan_buffer_unique_ptr.get();
336
- }
337
- if (unlikely(partition_id_cobhan_buffer == nullptr)) {
338
- return log_error_and_throw(env, "encrypt_string",
339
- "Failed to allocate partitionId cobhan buffer");
340
- }
341
-
342
- // Copy
343
- size_t partition_copied_bytes;
344
- partition_id_cobhan_buffer = copy_nstring_to_cbuffer(
345
- env, partition_id, partition_utf8_byte_length, partition_id_cobhan_buffer,
346
- &partition_copied_bytes);
347
- if (unlikely(partition_id_cobhan_buffer == nullptr)) {
348
- return log_error_and_throw(env, "encrypt_string",
349
- "Failed to copy partitionId to cobhan buffer");
350
- }
223
+ size_t partition_id_copied_bytes = 0;
224
+ NAPI_STRING_TO_CBUFFER(partition_id, partition_id_cobhan_buffer,
225
+ partition_id_copied_bytes, "encrypt_string");
351
226
 
352
- // Determine size
353
- size_t input_utf8_byte_length;
354
227
  Napi::String input = info[1].As<Napi::String>();
355
- input_utf8_byte_length = nstring_utf8_byte_length(env, input);
356
- if (unlikely(input_utf8_byte_length == (size_t)(-1))) {
357
- return log_error_and_throw(env, "encrypt_string",
358
- "Failed to get input utf8 length");
359
- }
360
- if (unlikely(input_utf8_byte_length == 0)) {
361
- return log_error_and_throw(env, "encrypt_string", "input is empty");
362
- }
363
-
364
- // Allocate
365
228
  char *input_cobhan_buffer;
366
- std::unique_ptr<char[]> input_cobhan_buffer_unique_ptr;
367
- if (input_utf8_byte_length < max_stack_alloc_size) {
368
- // If the buffer is small enough, allocate it on the stack
369
- size_t input_cobhan_buffer_size_bytes =
370
- calculate_cobhan_buffer_size_bytes(input_utf8_byte_length);
371
- debug_log_alloca("encrypt_string", "input_cobhan_buffer",
372
- input_cobhan_buffer_size_bytes);
373
- input_cobhan_buffer = (char *)alloca(input_cobhan_buffer_size_bytes);
374
- configure_cbuffer(input_cobhan_buffer, input_utf8_byte_length);
375
- } else {
376
- // Otherwise, allocate it on the heap
377
- input_cobhan_buffer_unique_ptr =
378
- heap_allocate_cbuffer("input_cobhan_buffer", input_utf8_byte_length);
379
- input_cobhan_buffer = input_cobhan_buffer_unique_ptr.get();
380
- }
381
- if (unlikely(input_cobhan_buffer == nullptr)) {
382
- return log_error_and_throw(env, "encrypt_string",
383
- "Failed to allocate input cobhan buffer");
384
- }
229
+ size_t input_copied_bytes = 0;
230
+ NAPI_STRING_TO_CBUFFER(input, input_cobhan_buffer, input_copied_bytes,
231
+ "encrypt_string");
385
232
 
386
- // Copy
387
- size_t input_copied_bytes;
388
- input_cobhan_buffer =
389
- copy_nstring_to_cbuffer(env, input, input_utf8_byte_length,
390
- input_cobhan_buffer, &input_copied_bytes);
391
- if (unlikely(input_cobhan_buffer == nullptr)) {
392
- return log_error_and_throw(env, "encrypt_string",
393
- "Failed to copy input to cobhan buffer");
394
- }
395
-
396
- Napi::Value output =
397
- encrypt_to_json(env, partition_copied_bytes, input_utf8_byte_length,
233
+ Napi::String output =
234
+ encrypt_to_json(env, partition_id_copied_bytes, input_copied_bytes,
398
235
  partition_id_cobhan_buffer, input_cobhan_buffer);
399
236
 
400
237
  if (unlikely(verbose_flag)) {
@@ -404,7 +241,7 @@ Napi::Value encrypt_string(const Napi::CallbackInfo &info) {
404
241
  return output;
405
242
  }
406
243
 
407
- Napi::Value decrypt(const Napi::CallbackInfo &info) {
244
+ Napi::Buffer<unsigned char> decrypt(const Napi::CallbackInfo &info) {
408
245
  Napi::Env env = info.Env();
409
246
 
410
247
  if (unlikely(verbose_flag)) {
@@ -412,129 +249,47 @@ Napi::Value decrypt(const Napi::CallbackInfo &info) {
412
249
  }
413
250
 
414
251
  if (unlikely(setup_state == 0)) {
415
- return log_error_and_throw(env, "decrypt", "setup() not called");
252
+ log_error_and_throw(env, "decrypt", "setup() not called");
416
253
  }
417
254
 
418
255
  if (unlikely(info.Length() < 2)) {
419
- return log_error_and_throw(env, "decrypt", "Wrong number of arguments");
256
+ log_error_and_throw(env, "decrypt", "Wrong number of arguments");
420
257
  }
421
258
 
422
259
  if (unlikely(!info[0].IsString() || !info[1].IsString())) {
423
- return log_error_and_throw(env, "decrypt", "Wrong argument types");
260
+ log_error_and_throw(env, "decrypt", "Wrong argument types");
424
261
  }
425
262
 
426
- // Determine size
427
- size_t partition_utf8_byte_length, partition_copied_bytes;
428
263
  Napi::String partition_id = info[0].As<Napi::String>();
429
- partition_utf8_byte_length = nstring_utf8_byte_length(env, partition_id);
430
- if (unlikely(partition_utf8_byte_length == (size_t)(-1))) {
431
- return log_error_and_throw(env, "decrypt",
432
- "Failed to get partition_id utf8 length");
433
- }
434
- if (unlikely(partition_utf8_byte_length == 0)) {
435
- return log_error_and_throw(env, "decrypt", "partition_id is empty");
436
- }
437
-
438
- // Allocate
439
264
  char *partition_id_cobhan_buffer;
440
- std::unique_ptr<char[]> partition_id_cobhan_buffer_unique_ptr;
441
- if (partition_utf8_byte_length < max_stack_alloc_size) {
442
- // If the buffer is small enough, allocate it on the stack
443
- size_t partition_id_cobhan_buffer_size_bytes =
444
- calculate_cobhan_buffer_size_bytes(partition_utf8_byte_length);
445
- debug_log_alloca("decrypt", "partition_id_cobhan_buffer",
446
- partition_id_cobhan_buffer_size_bytes);
447
- partition_id_cobhan_buffer =
448
- (char *)alloca(partition_id_cobhan_buffer_size_bytes);
449
- configure_cbuffer(partition_id_cobhan_buffer, partition_utf8_byte_length);
450
- } else {
451
- // Otherwise, allocate it on the heap
452
- partition_id_cobhan_buffer_unique_ptr = heap_allocate_cbuffer(
453
- "partition_id_cobhan_buffer", partition_utf8_byte_length);
454
- partition_id_cobhan_buffer = partition_id_cobhan_buffer_unique_ptr.get();
455
- }
456
- if (unlikely(partition_id_cobhan_buffer == nullptr)) {
457
- return log_error_and_throw(env, "decrypt",
458
- "Failed to allocate partition_id cobhan buffer");
459
- }
460
-
461
- // Copy
462
- partition_id_cobhan_buffer = copy_nstring_to_cbuffer(
463
- env, partition_id, partition_utf8_byte_length, partition_id_cobhan_buffer,
464
- &partition_copied_bytes);
465
- if (unlikely(partition_id_cobhan_buffer == nullptr)) {
466
- return log_error_and_throw(env, "decrypt",
467
- "Failed to copy partition_id to cobhan buffer");
468
- }
265
+ size_t partition_id_copied_bytes = 0;
266
+ NAPI_STRING_TO_CBUFFER(partition_id, partition_id_cobhan_buffer,
267
+ partition_id_copied_bytes, "decrypt");
469
268
 
470
- // Determine size
471
- size_t input_utf8_byte_length;
472
269
  Napi::String input = info[1].As<Napi::String>();
473
- input_utf8_byte_length = nstring_utf8_byte_length(env, input);
474
- if (unlikely(input_utf8_byte_length == (size_t)(-1))) {
475
- return log_error_and_throw(env, "decrypt",
476
- "Failed to get input utf8 length");
477
- }
478
- if (unlikely(input_utf8_byte_length == 0)) {
479
- return log_error_and_throw(env, "decrypt", "input is empty");
480
- }
481
-
482
- if (unlikely(verbose_flag)) {
483
- debug_log("decrypt",
484
- "input size " + std::to_string(input_utf8_byte_length));
485
- }
486
-
487
- // Allocate
488
270
  char *input_cobhan_buffer;
489
- std::unique_ptr<char[]> input_cobhan_buffer_unique_ptr;
490
- if (input_utf8_byte_length < max_stack_alloc_size) {
491
- // If the buffer is small enough, allocate it on the stack
492
- size_t input_cobhan_buffer_size_bytes =
493
- calculate_cobhan_buffer_size_bytes(input_utf8_byte_length);
494
- debug_log_alloca("decrypt", "input_cobhan_buffer",
495
- input_cobhan_buffer_size_bytes);
496
- input_cobhan_buffer = (char *)alloca(input_cobhan_buffer_size_bytes);
497
- configure_cbuffer(input_cobhan_buffer, input_utf8_byte_length);
498
- } else {
499
- // Otherwise, allocate it on the heap
500
- input_cobhan_buffer_unique_ptr =
501
- heap_allocate_cbuffer("input_cobhan_buffer", input_utf8_byte_length);
502
- input_cobhan_buffer = input_cobhan_buffer_unique_ptr.get();
503
- }
504
- if (unlikely(input_cobhan_buffer == nullptr)) {
505
- return log_error_and_throw(env, "decrypt",
506
- "Failed to allocate input cobhan buffer");
507
- }
508
-
509
- // Copy
510
- size_t input_copied_bytes;
511
- input_cobhan_buffer =
512
- copy_nstring_to_cbuffer(env, input, input_utf8_byte_length,
513
- input_cobhan_buffer, &input_copied_bytes);
514
- if (unlikely(input_cobhan_buffer == nullptr)) {
515
- return log_error_and_throw(env, "decrypt",
516
- "Failed to copy input to cobhan buffer");
517
- }
271
+ size_t input_copied_bytes = 0;
272
+ NAPI_STRING_TO_CBUFFER(input, input_cobhan_buffer, input_copied_bytes,
273
+ "decrypt");
518
274
 
519
275
  char *output_cobhan_buffer;
520
- std::unique_ptr<char[]> output_cobhan_buffer_unique_ptr;
521
- if (input_utf8_byte_length < max_stack_alloc_size) {
522
- // If the buffer is small enough, allocate it on the stack
523
- size_t output_cobhan_buffer_size_bytes =
524
- calculate_cobhan_buffer_size_bytes(input_utf8_byte_length);
525
- debug_log_alloca("decrypt", "output_cobhan_buffer",
526
- output_cobhan_buffer_size_bytes);
527
- output_cobhan_buffer = (char *)alloca(output_cobhan_buffer_size_bytes);
528
- configure_cbuffer(output_cobhan_buffer, input_utf8_byte_length);
529
- } else {
530
- // Otherwise, allocate it on the heap
531
- output_cobhan_buffer_unique_ptr =
532
- heap_allocate_cbuffer("output_cobhan_buffer", input_utf8_byte_length);
533
- output_cobhan_buffer = output_cobhan_buffer_unique_ptr.get();
276
+ ALLOCATE_OUTPUT_CBUFFER(output_cobhan_buffer, input_copied_bytes, "decrypt");
277
+
278
+ char *partition_id_canary_ptr = get_canary_ptr(partition_id_cobhan_buffer);
279
+ if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
280
+ log_error_and_throw(
281
+ env, "encrypt_to_json",
282
+ "Failed initial canary check for partition_id_cobhan_buffer");
283
+ }
284
+ char *input_canary_ptr = get_canary_ptr(input_cobhan_buffer);
285
+ if (unlikely(!check_canary_ptr(input_canary_ptr))) {
286
+ log_error_and_throw(env, "encrypt_to_json",
287
+ "Failed initial canary check for input_cobhan_buffer");
534
288
  }
535
- if (unlikely(output_cobhan_buffer == nullptr)) {
536
- return log_error_and_throw(env, "decrypt",
537
- "Failed to allocate cobhan output buffer");
289
+ char *output_canary_ptr = get_canary_ptr(output_cobhan_buffer);
290
+ if (unlikely(!check_canary_ptr(output_canary_ptr))) {
291
+ log_error_and_throw(env, "encrypt_to_json",
292
+ "Failed initial canary check for output_cobhan_buffer");
538
293
  }
539
294
 
540
295
  if (unlikely(verbose_flag)) {
@@ -550,12 +305,29 @@ Napi::Value decrypt(const Napi::CallbackInfo &info) {
550
305
  debug_log("decrypt", "Returned from asherah-cobhan DecryptFromJson");
551
306
  }
552
307
 
308
+ if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
309
+ log_error_and_throw(
310
+ env, "encrypt_to_json",
311
+ "Failed post-call canary check for partition_id_cobhan_buffer");
312
+ }
313
+ if (unlikely(!check_canary_ptr(input_canary_ptr))) {
314
+ log_error_and_throw(
315
+ env, "encrypt_to_json",
316
+ "Failed post-call canary check for input_cobhan_buffer");
317
+ }
318
+ if (unlikely(!check_canary_ptr(output_canary_ptr))) {
319
+ log_error_and_throw(
320
+ env, "encrypt_to_json",
321
+ "Failed post-call canary check for output_cobhan_buffer");
322
+ }
323
+
553
324
  if (unlikely(result < 0)) {
554
325
  // TODO: Convert this to a proper error message
555
- return log_error_and_throw(env, "decrypt", std::to_string(result));
326
+ log_error_and_throw(env, "decrypt", std::to_string(result));
556
327
  }
557
328
 
558
- Napi::Value output = cbuffer_to_nbuffer(env, output_cobhan_buffer);
329
+ Napi::Buffer<unsigned char> output =
330
+ cbuffer_to_nbuffer(env, output_cobhan_buffer);
559
331
 
560
332
  if (unlikely(verbose_flag)) {
561
333
  debug_log("decrypt", "finished");
@@ -564,7 +336,7 @@ Napi::Value decrypt(const Napi::CallbackInfo &info) {
564
336
  return output;
565
337
  }
566
338
 
567
- Napi::Value decrypt_string(const Napi::CallbackInfo &info) {
339
+ Napi::String decrypt_string(const Napi::CallbackInfo &info) {
568
340
  Napi::Env env = info.Env();
569
341
 
570
342
  if (unlikely(verbose_flag)) {
@@ -572,126 +344,48 @@ Napi::Value decrypt_string(const Napi::CallbackInfo &info) {
572
344
  }
573
345
 
574
346
  if (unlikely(setup_state == 0)) {
575
- return log_error_and_throw(env, "decrypt_string", "setup() not called");
347
+ log_error_and_throw(env, "decrypt_string", "setup() not called");
576
348
  }
577
349
 
578
350
  if (unlikely(info.Length() < 2)) {
579
- return log_error_and_throw(env, "decrypt_string",
580
- "Wrong number of arguments");
351
+ log_error_and_throw(env, "decrypt_string", "Wrong number of arguments");
581
352
  }
582
353
 
583
354
  if (unlikely(!info[0].IsString() || !info[1].IsString())) {
584
- return log_error_and_throw(env, "decrypt_string", "Wrong argument types");
355
+ log_error_and_throw(env, "decrypt_string", "Wrong argument types");
585
356
  }
586
357
 
587
- // Determine size
588
- size_t partition_utf8_byte_length;
589
358
  Napi::String partition_id = info[0].As<Napi::String>();
590
- partition_utf8_byte_length = nstring_utf8_byte_length(env, partition_id);
591
- if (unlikely(partition_utf8_byte_length == (size_t)(-1))) {
592
- return log_error_and_throw(env, "decrypt_string",
593
- "Failed to get partition_id utf8 length");
594
- }
595
- if (unlikely(partition_utf8_byte_length == 0)) {
596
- return log_error_and_throw(env, "decrypt_string", "partition_id is empty");
597
- }
598
-
599
- // Allocate
600
359
  char *partition_id_cobhan_buffer;
601
- std::unique_ptr<char[]> partition_id_cobhan_buffer_unique_ptr;
602
- if (partition_utf8_byte_length < max_stack_alloc_size) {
603
- // If the buffer is small enough, allocate it on the stack
604
- size_t partition_id_cobhan_buffer_size_bytes =
605
- calculate_cobhan_buffer_size_bytes(partition_utf8_byte_length);
606
- debug_log_alloca("decrypt_string", "partition_id_cobhan_buffer",
607
- partition_id_cobhan_buffer_size_bytes);
608
- partition_id_cobhan_buffer =
609
- (char *)alloca(partition_id_cobhan_buffer_size_bytes);
610
- configure_cbuffer(partition_id_cobhan_buffer, partition_utf8_byte_length);
611
- } else {
612
- // Otherwise, allocate it on the heap
613
- partition_id_cobhan_buffer_unique_ptr = heap_allocate_cbuffer(
614
- "partition_id_cobhan_buffer", partition_utf8_byte_length);
615
- partition_id_cobhan_buffer = partition_id_cobhan_buffer_unique_ptr.get();
616
- }
617
- if (unlikely(partition_id_cobhan_buffer == nullptr)) {
618
- return log_error_and_throw(env, "decrypt_string",
619
- "Failed to allocate partitionId cobhan buffer");
620
- }
621
-
622
- // Copy
623
- size_t partition_copied_bytes;
624
- partition_id_cobhan_buffer = copy_nstring_to_cbuffer(
625
- env, partition_id, partition_utf8_byte_length, partition_id_cobhan_buffer,
626
- &partition_copied_bytes);
627
- if (unlikely(partition_id_cobhan_buffer == nullptr)) {
628
- return log_error_and_throw(env, "decrypt_string",
629
- "Failed to copy partitionId to cobhan buffer");
630
- }
360
+ size_t partition_id_copied_bytes = 0;
361
+ NAPI_STRING_TO_CBUFFER(partition_id, partition_id_cobhan_buffer,
362
+ partition_id_copied_bytes, "decrypt_string");
631
363
 
632
- // Determine size
633
- size_t input_utf8_byte_length;
634
364
  Napi::String input = info[1].As<Napi::String>();
635
- input_utf8_byte_length = nstring_utf8_byte_length(env, input);
636
- if (unlikely(input_utf8_byte_length == (size_t)(-1))) {
637
- return log_error_and_throw(env, "decrypt_string",
638
- "Failed to get input utf8 length");
639
- }
640
- if (unlikely(input_utf8_byte_length == 0)) {
641
- return log_error_and_throw(env, "decrypt_string", "input is empty");
642
- }
643
-
644
- // Allocate
645
365
  char *input_cobhan_buffer;
646
- std::unique_ptr<char[]> input_cobhan_buffer_unique_ptr;
647
- if (input_utf8_byte_length < max_stack_alloc_size) {
648
- // If the buffer is small enough, allocate it on the stack
649
- size_t input_cobhan_buffer_size_bytes =
650
- calculate_cobhan_buffer_size_bytes(input_utf8_byte_length);
651
- debug_log_alloca("decrypt_string", "input_cobhan_buffer",
652
- input_cobhan_buffer_size_bytes);
653
- input_cobhan_buffer = (char *)alloca(input_cobhan_buffer_size_bytes);
654
- configure_cbuffer(input_cobhan_buffer, input_utf8_byte_length);
655
- } else {
656
- // Otherwise, allocate it on the heap
657
- input_cobhan_buffer_unique_ptr =
658
- heap_allocate_cbuffer("input_cobhan_buffer", input_utf8_byte_length);
659
- input_cobhan_buffer = input_cobhan_buffer_unique_ptr.get();
660
- }
661
- if (unlikely(input_cobhan_buffer == nullptr)) {
662
- return log_error_and_throw(env, "decrypt_string",
663
- "Failed to allocate input cobhan buffer");
664
- }
665
-
666
- // Copy
667
- size_t input_copied_bytes;
668
- input_cobhan_buffer =
669
- copy_nstring_to_cbuffer(env, input, input_utf8_byte_length,
670
- input_cobhan_buffer, &input_copied_bytes);
671
- if (unlikely(input_cobhan_buffer == nullptr)) {
672
- return log_error_and_throw(env, "decrypt_string",
673
- "Failed to copy input to cobhan buffer");
674
- }
366
+ size_t input_copied_bytes = 0;
367
+ NAPI_STRING_TO_CBUFFER(input, input_cobhan_buffer, input_copied_bytes,
368
+ "decrypt_string");
675
369
 
676
370
  char *output_cobhan_buffer;
677
- std::unique_ptr<char[]> output_cobhan_buffer_unique_ptr;
678
- if (input_utf8_byte_length < max_stack_alloc_size) {
679
- // If the buffer is small enough, allocate it on the stack
680
- size_t output_cobhan_buffer_size_bytes =
681
- calculate_cobhan_buffer_size_bytes(input_utf8_byte_length);
682
- debug_log_alloca("decrypt_string", "output_cobhan_buffer",
683
- output_cobhan_buffer_size_bytes);
684
- output_cobhan_buffer = (char *)alloca(output_cobhan_buffer_size_bytes);
685
- configure_cbuffer(output_cobhan_buffer, input_utf8_byte_length);
686
- } else {
687
- // Otherwise, allocate it on the heap
688
- output_cobhan_buffer_unique_ptr =
689
- heap_allocate_cbuffer("output_cobhan_buffer", input_utf8_byte_length);
690
- output_cobhan_buffer = output_cobhan_buffer_unique_ptr.get();
371
+ ALLOCATE_OUTPUT_CBUFFER(output_cobhan_buffer, input_copied_bytes,
372
+ "decrypt_string");
373
+
374
+ char *partition_id_canary_ptr = get_canary_ptr(partition_id_cobhan_buffer);
375
+ if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
376
+ log_error_and_throw(
377
+ env, "encrypt_to_json",
378
+ "Failed initial canary check for partition_id_cobhan_buffer");
379
+ }
380
+ char *input_canary_ptr = get_canary_ptr(input_cobhan_buffer);
381
+ if (unlikely(!check_canary_ptr(input_canary_ptr))) {
382
+ log_error_and_throw(env, "encrypt_to_json",
383
+ "Failed initial canary check for input_cobhan_buffer");
691
384
  }
692
- if (unlikely(output_cobhan_buffer == nullptr)) {
693
- return log_error_and_throw(env, "decrypt_string",
694
- "Failed to allocate cobhan output buffer");
385
+ char *output_canary_ptr = get_canary_ptr(output_cobhan_buffer);
386
+ if (unlikely(!check_canary_ptr(output_canary_ptr))) {
387
+ log_error_and_throw(env, "encrypt_to_json",
388
+ "Failed initial canary check for output_cobhan_buffer");
695
389
  }
696
390
 
697
391
  if (unlikely(verbose_flag)) {
@@ -707,12 +401,28 @@ Napi::Value decrypt_string(const Napi::CallbackInfo &info) {
707
401
  debug_log("decrypt_string", "Returned from asherah-cobhan DecryptFromJson");
708
402
  }
709
403
 
404
+ if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
405
+ log_error_and_throw(
406
+ env, "encrypt_to_json",
407
+ "Failed post-call canary check for partition_id_cobhan_buffer");
408
+ }
409
+ if (unlikely(!check_canary_ptr(input_canary_ptr))) {
410
+ log_error_and_throw(
411
+ env, "encrypt_to_json",
412
+ "Failed post-call canary check for input_cobhan_buffer");
413
+ }
414
+ if (unlikely(!check_canary_ptr(output_canary_ptr))) {
415
+ log_error_and_throw(
416
+ env, "encrypt_to_json",
417
+ "Failed post-call canary check for output_cobhan_buffer");
418
+ }
419
+
710
420
  if (unlikely(result < 0)) {
711
421
  // TODO: Convert this to a proper error message
712
- return log_error_and_throw(env, "decrypt_string", std::to_string(result));
422
+ log_error_and_throw(env, "decrypt_string", std::to_string(result));
713
423
  }
714
424
 
715
- Napi::Value output = cbuffer_to_nstring(env, output_cobhan_buffer);
425
+ Napi::String output = cbuffer_to_nstring(env, output_cobhan_buffer);
716
426
 
717
427
  if (unlikely(verbose_flag)) {
718
428
  debug_log("decrypt_string", "finished");
@@ -750,7 +460,6 @@ void set_max_stack_alloc_item_size(const Napi::CallbackInfo &info) {
750
460
  if (unlikely(info.Length() < 1)) {
751
461
  log_error_and_throw(env, "set_max_stack_alloc_item_size",
752
462
  "Wrong number of arguments");
753
- return;
754
463
  }
755
464
 
756
465
  Napi::Number item_size = info[0].ToNumber();
@@ -768,12 +477,11 @@ void set_safety_padding_overhead(const Napi::CallbackInfo &info) {
768
477
  if (unlikely(info.Length() < 1)) {
769
478
  log_error_and_throw(env, "set_safety_padding_overhead",
770
479
  "Wrong number of arguments");
771
- return;
772
480
  }
773
481
 
774
482
  Napi::Number safety_padding_number = info[0].ToNumber();
775
483
 
776
- safety_padding_bytes = (size_t)safety_padding_number.Int32Value();
484
+ *safety_padding_bytes_ptr = (size_t)safety_padding_number.Int32Value();
777
485
  }
778
486
 
779
487
  Napi::Object Init(Napi::Env env, Napi::Object exports) {
@@ -1,3 +1,11 @@
1
1
  #include <stddef.h>
2
- size_t est_intermediate_key_overhead = 0;
3
- size_t safety_padding_bytes = 0;
2
+ static size_t est_intermediate_key_overhead = 0;
3
+ static size_t safety_padding_bytes = 0;
4
+
5
+ size_t* get_est_intermediate_key_overhead_ptr() {
6
+ return &est_intermediate_key_overhead;
7
+ }
8
+
9
+ size_t* get_safety_padding_bytes_ptr() {
10
+ return &safety_padding_bytes;
11
+ }
@@ -2,17 +2,24 @@
2
2
  #define COBHAN_NAPI_INTEROP_H
3
3
  #include "hints.h"
4
4
  #include "logging.h"
5
- #include <string>
6
5
  #include <napi.h>
6
+ #include <string>
7
+
8
+ // Stupid hack to get around extern issues
9
+ size_t *get_est_intermediate_key_overhead_ptr();
10
+ size_t *get_safety_padding_bytes_ptr();
7
11
 
8
- extern size_t est_intermediate_key_overhead;
9
- extern size_t safety_padding_bytes;
12
+ size_t *est_intermediate_key_overhead_ptr =
13
+ get_est_intermediate_key_overhead_ptr();
14
+ size_t *safety_padding_bytes_ptr = get_safety_padding_bytes_ptr();
10
15
 
11
16
  const size_t est_encryption_overhead = 48;
12
17
  const size_t est_envelope_overhead = 185;
13
18
  const double base64_overhead = 1.34;
14
19
 
15
20
  const size_t cobhan_header_size_bytes = 64 / 8;
21
+ const size_t canary_size = sizeof(int32_t) * 2;
22
+ const int32_t canary_constant = 0xdeadbeef;
16
23
 
17
24
  std::string napi_status_to_string(napi_status status) {
18
25
  switch (status) {
@@ -70,19 +77,20 @@ cbuffer_byte_length(char *cobhan_buffer) {
70
77
  return *((int32_t *)cobhan_buffer);
71
78
  }
72
79
 
73
- __attribute__((always_inline)) inline Napi::Value
80
+ __attribute__((always_inline)) inline void
74
81
  log_error_and_throw(Napi::Env &env, const char *function_name,
75
82
  std::string error_msg) {
76
83
  error_log(function_name, error_msg);
77
84
  Napi::Error::New(env, function_name + (": " + error_msg))
78
85
  .ThrowAsJavaScriptException();
79
- return env.Null();
80
86
  }
81
87
 
82
88
  __attribute__((always_inline)) inline size_t
83
- calculate_cobhan_buffer_size_bytes(size_t data_len_bytes) {
84
- return data_len_bytes + cobhan_header_size_bytes + safety_padding_bytes +
85
- 1; // Add one for possible NULL delimiter due to Node string functions
89
+ calculate_cobhan_buffer_allocation_size(size_t data_len_bytes) {
90
+ return data_len_bytes + cobhan_header_size_bytes +
91
+ 1 + // Add one for possible NULL delimiter due to Node string functions
92
+ canary_size // Add space for canary value
93
+ + *safety_padding_bytes_ptr; // Add safety padding if configured
86
94
  }
87
95
 
88
96
  __attribute__((always_inline)) inline size_t
@@ -92,9 +100,9 @@ estimate_asherah_output_size_bytes(size_t data_byte_len,
92
100
  double est_data_byte_len =
93
101
  (double(data_byte_len + est_encryption_overhead) * base64_overhead) + 1;
94
102
 
95
- size_t asherah_output_size_bytes =
96
- size_t(est_envelope_overhead + est_intermediate_key_overhead +
97
- partition_byte_len + est_data_byte_len + safety_padding_bytes);
103
+ size_t asherah_output_size_bytes = size_t(
104
+ est_envelope_overhead + *est_intermediate_key_overhead_ptr +
105
+ partition_byte_len + est_data_byte_len + *safety_padding_bytes_ptr);
98
106
  if (unlikely(verbose_flag)) {
99
107
  std::string log_msg =
100
108
  "estimate_asherah_output_size(" + std::to_string(data_byte_len) + ", " +
@@ -107,56 +115,113 @@ estimate_asherah_output_size_bytes(size_t data_byte_len,
107
115
  return asherah_output_size_bytes;
108
116
  }
109
117
 
118
+ __attribute__((always_inline)) inline char *
119
+ cbuffer_data_ptr(char *cobhan_buffer) {
120
+ return cobhan_buffer + cobhan_header_size_bytes;
121
+ }
122
+
110
123
  __attribute__((always_inline)) inline void configure_cbuffer(char *buffer,
111
124
  size_t length) {
125
+ if (verbose_flag) {
126
+ debug_log("configure_cbuffer", "configure_cbuffer(" +
127
+ std::to_string((intptr_t)buffer) + ", " +
128
+ std::to_string(length) + ")");
129
+ }
130
+
112
131
  *((int32_t *)buffer) = length;
113
132
  // Reserved for future use
114
133
  *((int32_t *)(buffer + sizeof(int32_t))) = 0;
134
+
135
+ // Write canary values
136
+ char *data_ptr = cbuffer_data_ptr(buffer);
137
+ if (verbose_flag) {
138
+ debug_log("configure_cbuffer",
139
+ "Writing first canary at " +
140
+ std::to_string((intptr_t)(data_ptr + length + 1)));
141
+ }
142
+
143
+ // First canary value is a int32_t 0 which gives us four NULLs
144
+ *((int32_t *)(data_ptr + length + 1)) = 0;
145
+
146
+ if (verbose_flag) {
147
+ debug_log("configure_cbuffer",
148
+ "Writing second canary at " +
149
+ std::to_string(
150
+ (intptr_t)(data_ptr + length + 1 + sizeof(int32_t))));
151
+ }
152
+
153
+ // Second canary value is a int32_t 0xdeadbeef
154
+ *((int32_t *)(data_ptr + length + 1 + sizeof(int32_t))) = canary_constant;
155
+ }
156
+
157
+ __attribute__((always_inline)) inline char *
158
+ get_canary_ptr(char *cobhan_buffer) {
159
+ int32_t cobhan_buffer_size_bytes = cbuffer_byte_length(cobhan_buffer);
160
+ return cbuffer_data_ptr(cobhan_buffer) + cobhan_buffer_size_bytes + 1;
161
+ }
162
+
163
+ __attribute__((always_inline)) inline bool check_canary_ptr(char *canary_ptr) {
164
+ int32_t zero_value = *((int32_t *)(canary_ptr));
165
+ if (zero_value != 0) {
166
+ std::string error_msg =
167
+ "Canary check failed: " + std::to_string(zero_value) + " != 0";
168
+ error_log("canary_check_cbuffer", error_msg);
169
+ return false;
170
+ }
171
+ int32_t canary_value = *((int32_t *)(canary_ptr + sizeof(int32_t)));
172
+ if (canary_value != canary_constant) {
173
+ std::string error_msg =
174
+ "Canary check failed: " + std::to_string(canary_value) +
175
+ " != " + std::to_string(canary_constant);
176
+ error_log("canary_check_cbuffer", error_msg);
177
+ return false;
178
+ }
179
+ return true;
115
180
  }
116
181
 
117
182
  __attribute__((always_inline)) inline std::unique_ptr<char[]>
118
183
  heap_allocate_cbuffer(const char *variable_name, size_t size_bytes) {
119
- size_t cobhan_buffer_size_bytes =
120
- calculate_cobhan_buffer_size_bytes(size_bytes);
184
+ size_t cobhan_buffer_allocation_size =
185
+ calculate_cobhan_buffer_allocation_size(size_bytes);
121
186
  if (unlikely(verbose_flag)) {
122
187
  std::string log_msg =
123
188
  "heap_allocate_cbuffer(" + std::to_string(size_bytes) +
124
- ") (heap) cobhan_buffer_size_bytes: " +
125
- std::to_string(cobhan_buffer_size_bytes) + " for " + variable_name;
189
+ ") (heap) cobhan_buffer_allocation_size: " +
190
+ std::to_string(cobhan_buffer_allocation_size) + " for " + variable_name;
126
191
  debug_log("allocate_cbuffer", log_msg);
127
192
  }
128
193
 
129
- char *cobhan_buffer = new (std::nothrow) char[cobhan_buffer_size_bytes];
194
+ char *cobhan_buffer = new (std::nothrow) char[cobhan_buffer_allocation_size];
130
195
  if (unlikely(cobhan_buffer == nullptr)) {
131
- std::string error_msg =
132
- "new[" + std::to_string(cobhan_buffer_size_bytes) + " returned null";
196
+ std::string error_msg = "new[" +
197
+ std::to_string(cobhan_buffer_allocation_size) +
198
+ "] returned null";
133
199
  error_log("allocate_cbuffer", error_msg);
134
200
  return nullptr;
135
201
  }
136
202
  std::unique_ptr<char[]> cobhan_buffer_unique_ptr(cobhan_buffer);
137
- configure_cbuffer(cobhan_buffer, size_bytes + safety_padding_bytes);
203
+ configure_cbuffer(cobhan_buffer, size_bytes + *safety_padding_bytes_ptr);
138
204
  return cobhan_buffer_unique_ptr;
139
205
  }
140
206
 
141
- __attribute__((always_inline)) inline Napi::Value
207
+ __attribute__((always_inline)) inline Napi::String
142
208
  cbuffer_to_nstring(Napi::Env &env, char *cobhan_buffer) {
143
209
  napi_value output;
144
210
 
145
211
  int32_t cobhan_buffer_size_bytes = cbuffer_byte_length(cobhan_buffer);
146
212
  if (cobhan_buffer_size_bytes <= 0) {
147
- return log_error_and_throw(env, "cbuffer_to_nstring",
148
- "Invalid cobhan buffer byte length");
213
+ log_error_and_throw(env, "cbuffer_to_nstring",
214
+ "Invalid cobhan buffer byte length");
149
215
  }
150
216
 
151
217
  // Using C function because it allows length delimited input
152
218
  napi_status status = napi_create_string_utf8(
153
- env, ((const char *)cobhan_buffer) + cobhan_header_size_bytes,
154
- cobhan_buffer_size_bytes, &output);
219
+ env, cbuffer_data_ptr(cobhan_buffer), cobhan_buffer_size_bytes, &output);
155
220
 
156
221
  if (unlikely(status != napi_ok)) {
157
- return log_error_and_throw(env, "cbuffer_to_nstring",
158
- "napi_create_string_utf8 failed: " +
159
- napi_status_to_string(status));
222
+ log_error_and_throw(env, "cbuffer_to_nstring",
223
+ "napi_create_string_utf8 failed: " +
224
+ napi_status_to_string(status));
160
225
  }
161
226
 
162
227
  return Napi::String(env, output);
@@ -196,13 +261,21 @@ copy_nstring_to_cbuffer(Napi::Env &env, Napi::String &str,
196
261
  return nullptr;
197
262
  }
198
263
 
264
+ if (unlikely(verbose_flag)) {
265
+ debug_log("copy_nstring_to_cbuffer",
266
+ "Copying " + std::to_string(str_utf8_byte_length) + " bytes to " +
267
+ std::to_string((intptr_t)cbuffer_data_ptr(cobhan_buffer)) +
268
+ "-" +
269
+ std::to_string((intptr_t)(cbuffer_data_ptr(cobhan_buffer) +
270
+ str_utf8_byte_length)));
271
+ }
272
+
199
273
  napi_status status;
200
274
  size_t copied_bytes;
201
275
  // NOTE: This implementation relies on the additional byte that is reserved
202
276
  // upon allocation for a NULL delimiter as methods like
203
277
  // napi_get_value_string_utf8 append a NULL delimiter
204
- status = napi_get_value_string_utf8(env, str,
205
- cobhan_buffer + cobhan_header_size_bytes,
278
+ status = napi_get_value_string_utf8(env, str, cbuffer_data_ptr(cobhan_buffer),
206
279
  str_utf8_byte_length + 1, &copied_bytes);
207
280
  if (unlikely(status != napi_ok)) {
208
281
  log_error_and_throw(env, "copy_nstring_to_cbuffer",
@@ -244,18 +317,17 @@ copy_nbuffer_to_cbuffer(Napi::Env &env, Napi::Buffer<unsigned char> &nbuffer,
244
317
  "Buffer too large for cobhan buffer");
245
318
  return nullptr;
246
319
  }
247
- memcpy(cobhan_buffer + cobhan_header_size_bytes, nbuffer.Data(),
248
- nbuffer_byte_length);
320
+ memcpy(cbuffer_data_ptr(cobhan_buffer), nbuffer.Data(), nbuffer_byte_length);
249
321
  configure_cbuffer(cobhan_buffer, nbuffer_byte_length);
250
322
  return cobhan_buffer;
251
323
  }
252
324
 
253
- __attribute__((always_inline)) inline Napi::Value
325
+ __attribute__((always_inline)) inline Napi::Buffer<unsigned char>
254
326
  cbuffer_to_nbuffer(Napi::Env &env, char *cobhan_buffer) {
255
327
  int32_t cobhan_buffer_byte_length = cbuffer_byte_length(cobhan_buffer);
256
328
  if (unlikely(cobhan_buffer_byte_length <= 0)) {
257
- return log_error_and_throw(env, "cbuffer_to_nbuffer",
258
- "Invalid cobhan buffer byte length");
329
+ log_error_and_throw(env, "cbuffer_to_nbuffer",
330
+ "Invalid cobhan buffer byte length");
259
331
  }
260
332
 
261
333
  if (unlikely(verbose_flag)) {
@@ -269,8 +341,8 @@ cbuffer_to_nbuffer(Napi::Env &env, char *cobhan_buffer) {
269
341
  "Invalid cobhan buffer byte length");
270
342
  }
271
343
 
272
- Napi::Buffer nbuffer = Napi::Buffer<unsigned char>::Copy(
273
- env, ((unsigned char *)cobhan_buffer) + cobhan_header_size_bytes,
344
+ Napi::Buffer<unsigned char> nbuffer = Napi::Buffer<unsigned char>::Copy(
345
+ env, (const unsigned char *)cbuffer_data_ptr(cobhan_buffer),
274
346
  cobhan_buffer_byte_length);
275
347
 
276
348
  if (unlikely(verbose_flag)) {
@@ -281,4 +353,115 @@ cbuffer_to_nbuffer(Napi::Env &env, char *cobhan_buffer) {
281
353
  return nbuffer;
282
354
  }
283
355
 
356
+ // These are macros due to the use of alloca()
357
+
358
+ #define NAPI_STRING_TO_CBUFFER(napi_string, cobhan_buffer, bytes_copied, \
359
+ function_name) \
360
+ std::unique_ptr<char[]> napi_string##_cobhan_buffer_unique_ptr; \
361
+ do { \
362
+ /* Determine size */ \
363
+ size_t napi_string##_utf8_byte_length = \
364
+ nstring_utf8_byte_length(env, napi_string); \
365
+ if (unlikely(napi_string##_utf8_byte_length == (size_t)(-1))) { \
366
+ log_error_and_throw(env, function_name, \
367
+ "Failed to get " #napi_string " utf8 length"); \
368
+ } \
369
+ if (unlikely(napi_string##_utf8_byte_length == 0)) { \
370
+ log_error_and_throw(env, function_name, #napi_string " is empty"); \
371
+ } \
372
+ /* Allocate */ \
373
+ if (napi_string##_utf8_byte_length < max_stack_alloc_size) { \
374
+ /* If the buffer is small enough, allocate it on the stack */ \
375
+ size_t napi_string##_cobhan_buffer_allocation_size = \
376
+ calculate_cobhan_buffer_allocation_size( \
377
+ napi_string##_utf8_byte_length); \
378
+ debug_log_alloca(function_name, #napi_string "_cobhan_buffer", \
379
+ napi_string##_cobhan_buffer_allocation_size); \
380
+ cobhan_buffer = \
381
+ (char *)alloca(napi_string##_cobhan_buffer_allocation_size); \
382
+ configure_cbuffer(cobhan_buffer, napi_string##_utf8_byte_length); \
383
+ } else { \
384
+ /* Otherwise, allocate it on the heap */ \
385
+ napi_string##_cobhan_buffer_unique_ptr = heap_allocate_cbuffer( \
386
+ #cobhan_buffer, napi_string##_utf8_byte_length); \
387
+ cobhan_buffer = napi_string##_cobhan_buffer_unique_ptr.get(); \
388
+ } \
389
+ if (unlikely(cobhan_buffer == nullptr)) { \
390
+ log_error_and_throw(env, function_name, \
391
+ "Failed to allocate " #napi_string \
392
+ " cobhan buffer"); \
393
+ } \
394
+ /* Copy */ \
395
+ cobhan_buffer = copy_nstring_to_cbuffer(env, napi_string, \
396
+ napi_string##_utf8_byte_length, \
397
+ cobhan_buffer, &bytes_copied); \
398
+ if (unlikely(cobhan_buffer == nullptr)) { \
399
+ log_error_and_throw(env, function_name, \
400
+ "Failed to copy " #napi_string " to cobhan buffer"); \
401
+ } \
402
+ } while (0);
403
+
404
+ #define NAPI_BUFFER_TO_CBUFFER(napi_buffer, cobhan_buffer, bytes_copied, \
405
+ function_name) \
406
+ std::unique_ptr<char[]> napi_buffer##_unique_ptr; \
407
+ do { \
408
+ /* Determine size */ \
409
+ size_t napi_buffer##_byte_length = napi_buffer.ByteLength(); \
410
+ if (unlikely(napi_buffer##_byte_length == 0)) { \
411
+ log_error_and_throw(env, function_name, #napi_buffer " is empty"); \
412
+ } \
413
+ /* Allocate */ \
414
+ if (napi_buffer##_byte_length < max_stack_alloc_size) { \
415
+ /* If the buffer is small enough, allocate it on the stack */ \
416
+ size_t napi_buffer##_cobhan_buffer_allocation_size = \
417
+ calculate_cobhan_buffer_allocation_size(napi_buffer##_byte_length); \
418
+ debug_log_alloca(function_name, #cobhan_buffer, \
419
+ napi_buffer##_cobhan_buffer_allocation_size); \
420
+ cobhan_buffer = \
421
+ (char *)alloca(napi_buffer##_cobhan_buffer_allocation_size); \
422
+ configure_cbuffer(cobhan_buffer, napi_buffer##_byte_length); \
423
+ } else { \
424
+ /* Otherwise, allocate it on the heap */ \
425
+ napi_buffer##_unique_ptr = \
426
+ heap_allocate_cbuffer(#cobhan_buffer, napi_buffer##_byte_length); \
427
+ cobhan_buffer = napi_buffer##_unique_ptr.get(); \
428
+ } \
429
+ if (unlikely(cobhan_buffer == nullptr)) { \
430
+ log_error_and_throw( \
431
+ env, function_name, \
432
+ "Failed to allocate cobhan buffer for " #napi_buffer); \
433
+ } \
434
+ /* Copy */ \
435
+ cobhan_buffer = copy_nbuffer_to_cbuffer(env, napi_buffer, cobhan_buffer); \
436
+ if (unlikely(cobhan_buffer == nullptr)) { \
437
+ log_error_and_throw(env, function_name, \
438
+ "Failed to copy " #napi_buffer " to cobhan buffer"); \
439
+ } \
440
+ bytes_copied = napi_buffer##_byte_length; \
441
+ } while (0);
442
+
443
+ #define ALLOCATE_OUTPUT_CBUFFER(cobhan_buffer, buffer_size, function_name) \
444
+ std::unique_ptr<char[]> cobhan_buffer##_unique_ptr; \
445
+ do { \
446
+ if (buffer_size < max_stack_alloc_size) { \
447
+ /* If the buffer is small enough, allocate it on the stack */ \
448
+ size_t cobhan_buffer##_cobhan_buffer_allocation_size = \
449
+ calculate_cobhan_buffer_allocation_size(buffer_size); \
450
+ debug_log_alloca(function_name, #cobhan_buffer, \
451
+ cobhan_buffer##_cobhan_buffer_allocation_size); \
452
+ cobhan_buffer = \
453
+ (char *)alloca(cobhan_buffer##_cobhan_buffer_allocation_size); \
454
+ configure_cbuffer(cobhan_buffer, buffer_size); \
455
+ } else { \
456
+ /* Otherwise, allocate it on the heap */ \
457
+ cobhan_buffer##_unique_ptr = \
458
+ heap_allocate_cbuffer(#cobhan_buffer, buffer_size); \
459
+ cobhan_buffer = output_cobhan_buffer_unique_ptr.get(); \
460
+ } \
461
+ if (unlikely(cobhan_buffer == nullptr)) { \
462
+ log_error_and_throw(env, function_name, \
463
+ "Failed to allocate " #cobhan_buffer); \
464
+ } \
465
+ } while (0);
466
+
284
467
  #endif