asherah 1.3.20 → 1.3.22
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/binding.gyp +6 -3
- package/package.json +3 -1
- package/src/asherah.cc +85 -73
- package/src/cobhan.cc +2 -0
- package/src/cobhan.h +150 -0
- package/src/cobhan_napi_interop.cc +1 -10
- package/src/cobhan_napi_interop.h +70 -255
- package/src/logging.cc +1 -1
- package/src/logging.h +33 -1
package/binding.gyp
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
{
|
|
4
4
|
'target_name': 'asherah',
|
|
5
5
|
'include_dirs': ["<!(node -p \"require('node-addon-api').include_dir\")"],
|
|
6
|
-
"cflags": ["-fexceptions", "-g", "-O3"],
|
|
7
|
-
"cflags_cc": ["-fexceptions", "-g", "-O3"],
|
|
6
|
+
"cflags": ["-fexceptions", "-g", "-O3", "-std=c++17"],
|
|
7
|
+
"cflags_cc": ["-fexceptions", "-g", "-O3", "-std=c++17"],
|
|
8
8
|
"cflags!": [ "-fno-exceptions"],
|
|
9
9
|
"cflags_cc!": [ "-fno-exceptions" ],
|
|
10
10
|
'xcode_settings': {
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
'OTHER_CFLAGS': [
|
|
13
13
|
'-fexceptions',
|
|
14
14
|
'-g',
|
|
15
|
-
'-O3'
|
|
15
|
+
'-O3',
|
|
16
|
+
'-std=c++17'
|
|
16
17
|
],
|
|
17
18
|
},
|
|
18
19
|
'defines': [ 'NAPI_CPP_EXCEPTIONS', 'NODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS', 'NODE_ADDON_API_DISABLE_DEPRECATED', 'NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED' ],
|
|
@@ -23,6 +24,8 @@
|
|
|
23
24
|
'src/logging.h',
|
|
24
25
|
'src/cobhan_napi_interop.cc',
|
|
25
26
|
'src/cobhan_napi_interop.h',
|
|
27
|
+
'src/cobhan.h',
|
|
28
|
+
'src/cobhan.cc',
|
|
26
29
|
'src/hints.h'
|
|
27
30
|
],
|
|
28
31
|
'libraries': [ '../lib/libasherah.a' ]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "asherah",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.22",
|
|
4
4
|
"description": "Asherah envelope encryption and key rotation library",
|
|
5
5
|
"exports": {
|
|
6
6
|
"node-addons": "./dist/asherah.node"
|
|
@@ -28,6 +28,8 @@
|
|
|
28
28
|
"src/logging.cc",
|
|
29
29
|
"src/cobhan_napi_interop.h",
|
|
30
30
|
"src/cobhan_napi_interop.cc",
|
|
31
|
+
"src/cobhan.h",
|
|
32
|
+
"src/cobhan.cc",
|
|
31
33
|
"src/asherah.d.ts",
|
|
32
34
|
"scripts/download-libraries.sh",
|
|
33
35
|
"scripts/build.sh",
|
package/src/asherah.cc
CHANGED
|
@@ -3,28 +3,31 @@
|
|
|
3
3
|
#include "hints.h"
|
|
4
4
|
#include "logging.h"
|
|
5
5
|
#include <iostream>
|
|
6
|
+
#include <mutex>
|
|
6
7
|
#include <napi.h>
|
|
7
8
|
|
|
8
9
|
size_t max_stack_alloc_size = 2048;
|
|
9
10
|
int32_t setup_state = 0;
|
|
11
|
+
std::mutex asherah_lock;
|
|
10
12
|
|
|
11
13
|
void setup(const Napi::CallbackInfo &info) {
|
|
12
|
-
|
|
14
|
+
std::lock_guard<std::mutex> lock(asherah_lock);
|
|
13
15
|
|
|
14
16
|
if (unlikely(verbose_flag)) {
|
|
15
17
|
debug_log("setup", "called");
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
if (unlikely(setup_state == 1)) {
|
|
19
|
-
log_error_and_throw(
|
|
21
|
+
log_error_and_throw("setup", "setup called twice");
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
if (unlikely(info.Length() < 1)) {
|
|
23
|
-
log_error_and_throw(
|
|
25
|
+
log_error_and_throw("setup", "Wrong number of arguments");
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
Napi::String config;
|
|
27
29
|
Napi::Object config_json;
|
|
30
|
+
Napi::Env env = info.Env();
|
|
28
31
|
Napi::Object json = env.Global().Get("JSON").As<Napi::Object>();
|
|
29
32
|
if (likely(info[0].IsObject())) {
|
|
30
33
|
config_json = info[0].As<Napi::Object>();
|
|
@@ -35,13 +38,13 @@ void setup(const Napi::CallbackInfo &info) {
|
|
|
35
38
|
Napi::Function parse = json.Get("parse").As<Napi::Function>();
|
|
36
39
|
config_json = parse.Call(json, {config}).As<Napi::Object>();
|
|
37
40
|
} else {
|
|
38
|
-
log_error_and_throw(
|
|
41
|
+
log_error_and_throw("setup", "Wrong argument type");
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
Napi::String product_id = config_json.Get("ProductID").As<Napi::String>();
|
|
42
45
|
Napi::String service_name = config_json.Get("ServiceName").As<Napi::String>();
|
|
43
46
|
|
|
44
|
-
|
|
47
|
+
est_intermediate_key_overhead =
|
|
45
48
|
product_id.Utf8Value().length() + service_name.Utf8Value().length();
|
|
46
49
|
|
|
47
50
|
Napi::Value verbose = config_json.Get("Verbose");
|
|
@@ -54,13 +57,13 @@ void setup(const Napi::CallbackInfo &info) {
|
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
char *config_cobhan_buffer;
|
|
57
|
-
size_t config_copied_bytes
|
|
58
|
-
NAPI_STRING_TO_CBUFFER(config, config_cobhan_buffer, config_copied_bytes,
|
|
60
|
+
size_t config_copied_bytes;
|
|
61
|
+
NAPI_STRING_TO_CBUFFER(env, config, config_cobhan_buffer, config_copied_bytes,
|
|
59
62
|
"setup");
|
|
60
63
|
|
|
61
64
|
char *config_canary_ptr = get_canary_ptr(config_cobhan_buffer);
|
|
62
65
|
if (unlikely(!check_canary_ptr(config_canary_ptr))) {
|
|
63
|
-
log_error_and_throw(
|
|
66
|
+
log_error_and_throw("encrypt_to_json",
|
|
64
67
|
"Failed initial canary check for config_cobhan_buffer");
|
|
65
68
|
}
|
|
66
69
|
|
|
@@ -73,13 +76,13 @@ void setup(const Napi::CallbackInfo &info) {
|
|
|
73
76
|
|
|
74
77
|
if (unlikely(!check_canary_ptr(config_canary_ptr))) {
|
|
75
78
|
log_error_and_throw(
|
|
76
|
-
|
|
79
|
+
"encrypt_to_json",
|
|
77
80
|
"Failed post-call canary check for config_cobhan_buffer");
|
|
78
81
|
}
|
|
79
82
|
|
|
80
83
|
if (unlikely(result < 0)) {
|
|
81
84
|
// TODO: Convert this to a proper error message
|
|
82
|
-
log_error_and_throw(
|
|
85
|
+
log_error_and_throw("setup", std::to_string(result));
|
|
83
86
|
}
|
|
84
87
|
setup_state = 1;
|
|
85
88
|
}
|
|
@@ -98,23 +101,23 @@ Napi::String encrypt_to_json(Napi::Env &env, size_t partition_bytes,
|
|
|
98
101
|
}
|
|
99
102
|
|
|
100
103
|
char *output_cobhan_buffer;
|
|
101
|
-
|
|
102
|
-
|
|
104
|
+
ALLOCATE_CBUFFER(output_cobhan_buffer, asherah_output_size_bytes,
|
|
105
|
+
"encrypt_to_json");
|
|
103
106
|
|
|
104
107
|
char *partition_id_canary_ptr = get_canary_ptr(partition_id_cobhan_buffer);
|
|
105
108
|
if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
|
|
106
109
|
log_error_and_throw(
|
|
107
|
-
|
|
110
|
+
"encrypt_to_json",
|
|
108
111
|
"Failed initial canary check for partition_id_cobhan_buffer");
|
|
109
112
|
}
|
|
110
113
|
char *input_canary_ptr = get_canary_ptr(input_cobhan_buffer);
|
|
111
114
|
if (unlikely(!check_canary_ptr(input_canary_ptr))) {
|
|
112
|
-
log_error_and_throw(
|
|
115
|
+
log_error_and_throw("encrypt_to_json",
|
|
113
116
|
"Failed initial canary check for input_cobhan_buffer");
|
|
114
117
|
}
|
|
115
118
|
char *output_canary_ptr = get_canary_ptr(output_cobhan_buffer);
|
|
116
119
|
if (unlikely(!check_canary_ptr(output_canary_ptr))) {
|
|
117
|
-
log_error_and_throw(
|
|
120
|
+
log_error_and_throw("encrypt_to_json",
|
|
118
121
|
"Failed initial canary check for output_cobhan_buffer");
|
|
119
122
|
}
|
|
120
123
|
|
|
@@ -133,23 +136,23 @@ Napi::String encrypt_to_json(Napi::Env &env, size_t partition_bytes,
|
|
|
133
136
|
|
|
134
137
|
if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
|
|
135
138
|
log_error_and_throw(
|
|
136
|
-
|
|
139
|
+
"encrypt_to_json",
|
|
137
140
|
"Failed post-call canary check for partition_id_cobhan_buffer");
|
|
138
141
|
}
|
|
139
142
|
if (unlikely(!check_canary_ptr(input_canary_ptr))) {
|
|
140
143
|
log_error_and_throw(
|
|
141
|
-
|
|
144
|
+
"encrypt_to_json",
|
|
142
145
|
"Failed post-call canary check for input_cobhan_buffer");
|
|
143
146
|
}
|
|
144
147
|
if (unlikely(!check_canary_ptr(output_canary_ptr))) {
|
|
145
148
|
log_error_and_throw(
|
|
146
|
-
|
|
149
|
+
"encrypt_to_json",
|
|
147
150
|
"Failed post-call canary check for output_cobhan_buffer");
|
|
148
151
|
}
|
|
149
152
|
|
|
150
153
|
if (unlikely(result < 0)) {
|
|
151
154
|
// TODO: Convert this to a proper error message
|
|
152
|
-
log_error_and_throw(
|
|
155
|
+
log_error_and_throw("encrypt_to_json", std::to_string(result));
|
|
153
156
|
}
|
|
154
157
|
|
|
155
158
|
Napi::String output = cbuffer_to_nstring(env, output_cobhan_buffer);
|
|
@@ -157,35 +160,37 @@ Napi::String encrypt_to_json(Napi::Env &env, size_t partition_bytes,
|
|
|
157
160
|
}
|
|
158
161
|
|
|
159
162
|
Napi::String encrypt(const Napi::CallbackInfo &info) {
|
|
160
|
-
|
|
163
|
+
std::lock_guard<std::mutex> lock(asherah_lock);
|
|
161
164
|
|
|
162
165
|
if (unlikely(verbose_flag)) {
|
|
163
166
|
debug_log("encrypt", "called");
|
|
164
167
|
}
|
|
165
168
|
|
|
166
169
|
if (unlikely(setup_state == 0)) {
|
|
167
|
-
log_error_and_throw(
|
|
170
|
+
log_error_and_throw("encrypt", "setup() not called");
|
|
168
171
|
}
|
|
169
172
|
|
|
170
173
|
if (unlikely(info.Length() < 2)) {
|
|
171
|
-
log_error_and_throw(
|
|
174
|
+
log_error_and_throw("encrypt", "Wrong number of arguments");
|
|
172
175
|
}
|
|
173
176
|
|
|
174
177
|
if (unlikely(!info[0].IsString() || !info[1].IsBuffer())) {
|
|
175
|
-
log_error_and_throw(
|
|
178
|
+
log_error_and_throw("encrypt", "Wrong argument types");
|
|
176
179
|
}
|
|
177
180
|
|
|
181
|
+
Napi::Env env = info.Env();
|
|
182
|
+
|
|
178
183
|
Napi::String partition_id = info[0].As<Napi::String>();
|
|
179
184
|
char *partition_id_cobhan_buffer;
|
|
180
|
-
size_t partition_id_copied_bytes
|
|
181
|
-
NAPI_STRING_TO_CBUFFER(partition_id, partition_id_cobhan_buffer,
|
|
185
|
+
size_t partition_id_copied_bytes;
|
|
186
|
+
NAPI_STRING_TO_CBUFFER(env, partition_id, partition_id_cobhan_buffer,
|
|
182
187
|
partition_id_copied_bytes, "encrypt");
|
|
183
188
|
|
|
184
189
|
Napi::Buffer<unsigned char> input_napi_buffer =
|
|
185
190
|
info[1].As<Napi::Buffer<unsigned char>>();
|
|
186
191
|
char *input_cobhan_buffer;
|
|
187
|
-
size_t input_copied_bytes
|
|
188
|
-
NAPI_BUFFER_TO_CBUFFER(input_napi_buffer, input_cobhan_buffer,
|
|
192
|
+
size_t input_copied_bytes;
|
|
193
|
+
NAPI_BUFFER_TO_CBUFFER(env, input_napi_buffer, input_cobhan_buffer,
|
|
189
194
|
input_copied_bytes, "encrypt");
|
|
190
195
|
|
|
191
196
|
Napi::String output =
|
|
@@ -200,34 +205,36 @@ Napi::String encrypt(const Napi::CallbackInfo &info) {
|
|
|
200
205
|
}
|
|
201
206
|
|
|
202
207
|
Napi::String encrypt_string(const Napi::CallbackInfo &info) {
|
|
203
|
-
|
|
208
|
+
std::lock_guard<std::mutex> lock(asherah_lock);
|
|
204
209
|
|
|
205
210
|
if (unlikely(verbose_flag)) {
|
|
206
211
|
debug_log("encrypt_string", "called");
|
|
207
212
|
}
|
|
208
213
|
|
|
209
214
|
if (unlikely(setup_state == 0)) {
|
|
210
|
-
log_error_and_throw(
|
|
215
|
+
log_error_and_throw("encrypt_string", "setup() not called");
|
|
211
216
|
}
|
|
212
217
|
|
|
213
218
|
if (unlikely(info.Length() < 2)) {
|
|
214
|
-
log_error_and_throw(
|
|
219
|
+
log_error_and_throw("encrypt_string", "Wrong number of arguments");
|
|
215
220
|
}
|
|
216
221
|
|
|
217
222
|
if (unlikely(!info[0].IsString() || !info[1].IsString())) {
|
|
218
|
-
log_error_and_throw(
|
|
223
|
+
log_error_and_throw("encrypt_string", "Wrong argument types");
|
|
219
224
|
}
|
|
220
225
|
|
|
226
|
+
Napi::Env env = info.Env();
|
|
227
|
+
|
|
221
228
|
Napi::String partition_id = info[0].As<Napi::String>();
|
|
222
229
|
char *partition_id_cobhan_buffer;
|
|
223
|
-
size_t partition_id_copied_bytes
|
|
224
|
-
NAPI_STRING_TO_CBUFFER(partition_id, partition_id_cobhan_buffer,
|
|
230
|
+
size_t partition_id_copied_bytes;
|
|
231
|
+
NAPI_STRING_TO_CBUFFER(env, partition_id, partition_id_cobhan_buffer,
|
|
225
232
|
partition_id_copied_bytes, "encrypt_string");
|
|
226
233
|
|
|
227
234
|
Napi::String input = info[1].As<Napi::String>();
|
|
228
235
|
char *input_cobhan_buffer;
|
|
229
|
-
size_t input_copied_bytes
|
|
230
|
-
NAPI_STRING_TO_CBUFFER(input, input_cobhan_buffer, input_copied_bytes,
|
|
236
|
+
size_t input_copied_bytes;
|
|
237
|
+
NAPI_STRING_TO_CBUFFER(env, input, input_cobhan_buffer, input_copied_bytes,
|
|
231
238
|
"encrypt_string");
|
|
232
239
|
|
|
233
240
|
Napi::String output =
|
|
@@ -242,53 +249,55 @@ Napi::String encrypt_string(const Napi::CallbackInfo &info) {
|
|
|
242
249
|
}
|
|
243
250
|
|
|
244
251
|
Napi::Buffer<unsigned char> decrypt(const Napi::CallbackInfo &info) {
|
|
245
|
-
|
|
252
|
+
std::lock_guard<std::mutex> lock(asherah_lock);
|
|
246
253
|
|
|
247
254
|
if (unlikely(verbose_flag)) {
|
|
248
255
|
debug_log("decrypt", "called");
|
|
249
256
|
}
|
|
250
257
|
|
|
251
258
|
if (unlikely(setup_state == 0)) {
|
|
252
|
-
log_error_and_throw(
|
|
259
|
+
log_error_and_throw("decrypt", "setup() not called");
|
|
253
260
|
}
|
|
254
261
|
|
|
255
262
|
if (unlikely(info.Length() < 2)) {
|
|
256
|
-
log_error_and_throw(
|
|
263
|
+
log_error_and_throw("decrypt", "Wrong number of arguments");
|
|
257
264
|
}
|
|
258
265
|
|
|
259
266
|
if (unlikely(!info[0].IsString() || !info[1].IsString())) {
|
|
260
|
-
log_error_and_throw(
|
|
267
|
+
log_error_and_throw("decrypt", "Wrong argument types");
|
|
261
268
|
}
|
|
262
269
|
|
|
270
|
+
Napi::Env env = info.Env();
|
|
271
|
+
|
|
263
272
|
Napi::String partition_id = info[0].As<Napi::String>();
|
|
264
273
|
char *partition_id_cobhan_buffer;
|
|
265
|
-
size_t partition_id_copied_bytes
|
|
266
|
-
NAPI_STRING_TO_CBUFFER(partition_id, partition_id_cobhan_buffer,
|
|
274
|
+
size_t partition_id_copied_bytes;
|
|
275
|
+
NAPI_STRING_TO_CBUFFER(env, partition_id, partition_id_cobhan_buffer,
|
|
267
276
|
partition_id_copied_bytes, "decrypt");
|
|
268
277
|
|
|
269
278
|
Napi::String input = info[1].As<Napi::String>();
|
|
270
279
|
char *input_cobhan_buffer;
|
|
271
|
-
size_t input_copied_bytes
|
|
272
|
-
NAPI_STRING_TO_CBUFFER(input, input_cobhan_buffer, input_copied_bytes,
|
|
280
|
+
size_t input_copied_bytes;
|
|
281
|
+
NAPI_STRING_TO_CBUFFER(env, input, input_cobhan_buffer, input_copied_bytes,
|
|
273
282
|
"decrypt");
|
|
274
283
|
|
|
275
284
|
char *output_cobhan_buffer;
|
|
276
|
-
|
|
285
|
+
ALLOCATE_CBUFFER(output_cobhan_buffer, input_copied_bytes, "decrypt");
|
|
277
286
|
|
|
278
287
|
char *partition_id_canary_ptr = get_canary_ptr(partition_id_cobhan_buffer);
|
|
279
288
|
if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
|
|
280
289
|
log_error_and_throw(
|
|
281
|
-
|
|
290
|
+
"encrypt_to_json",
|
|
282
291
|
"Failed initial canary check for partition_id_cobhan_buffer");
|
|
283
292
|
}
|
|
284
293
|
char *input_canary_ptr = get_canary_ptr(input_cobhan_buffer);
|
|
285
294
|
if (unlikely(!check_canary_ptr(input_canary_ptr))) {
|
|
286
|
-
log_error_and_throw(
|
|
295
|
+
log_error_and_throw("encrypt_to_json",
|
|
287
296
|
"Failed initial canary check for input_cobhan_buffer");
|
|
288
297
|
}
|
|
289
298
|
char *output_canary_ptr = get_canary_ptr(output_cobhan_buffer);
|
|
290
299
|
if (unlikely(!check_canary_ptr(output_canary_ptr))) {
|
|
291
|
-
log_error_and_throw(
|
|
300
|
+
log_error_and_throw("encrypt_to_json",
|
|
292
301
|
"Failed initial canary check for output_cobhan_buffer");
|
|
293
302
|
}
|
|
294
303
|
|
|
@@ -307,23 +316,23 @@ Napi::Buffer<unsigned char> decrypt(const Napi::CallbackInfo &info) {
|
|
|
307
316
|
|
|
308
317
|
if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
|
|
309
318
|
log_error_and_throw(
|
|
310
|
-
|
|
319
|
+
"encrypt_to_json",
|
|
311
320
|
"Failed post-call canary check for partition_id_cobhan_buffer");
|
|
312
321
|
}
|
|
313
322
|
if (unlikely(!check_canary_ptr(input_canary_ptr))) {
|
|
314
323
|
log_error_and_throw(
|
|
315
|
-
|
|
324
|
+
"encrypt_to_json",
|
|
316
325
|
"Failed post-call canary check for input_cobhan_buffer");
|
|
317
326
|
}
|
|
318
327
|
if (unlikely(!check_canary_ptr(output_canary_ptr))) {
|
|
319
328
|
log_error_and_throw(
|
|
320
|
-
|
|
329
|
+
"encrypt_to_json",
|
|
321
330
|
"Failed post-call canary check for output_cobhan_buffer");
|
|
322
331
|
}
|
|
323
332
|
|
|
324
333
|
if (unlikely(result < 0)) {
|
|
325
334
|
// TODO: Convert this to a proper error message
|
|
326
|
-
log_error_and_throw(
|
|
335
|
+
log_error_and_throw("decrypt", std::to_string(result));
|
|
327
336
|
}
|
|
328
337
|
|
|
329
338
|
Napi::Buffer<unsigned char> output =
|
|
@@ -337,54 +346,55 @@ Napi::Buffer<unsigned char> decrypt(const Napi::CallbackInfo &info) {
|
|
|
337
346
|
}
|
|
338
347
|
|
|
339
348
|
Napi::String decrypt_string(const Napi::CallbackInfo &info) {
|
|
340
|
-
|
|
349
|
+
std::lock_guard<std::mutex> lock(asherah_lock);
|
|
341
350
|
|
|
342
351
|
if (unlikely(verbose_flag)) {
|
|
343
352
|
debug_log("decrypt_string", "called");
|
|
344
353
|
}
|
|
345
354
|
|
|
346
355
|
if (unlikely(setup_state == 0)) {
|
|
347
|
-
log_error_and_throw(
|
|
356
|
+
log_error_and_throw("decrypt_string", "setup() not called");
|
|
348
357
|
}
|
|
349
358
|
|
|
350
359
|
if (unlikely(info.Length() < 2)) {
|
|
351
|
-
log_error_and_throw(
|
|
360
|
+
log_error_and_throw("decrypt_string", "Wrong number of arguments");
|
|
352
361
|
}
|
|
353
362
|
|
|
354
363
|
if (unlikely(!info[0].IsString() || !info[1].IsString())) {
|
|
355
|
-
log_error_and_throw(
|
|
364
|
+
log_error_and_throw("decrypt_string", "Wrong argument types");
|
|
356
365
|
}
|
|
357
366
|
|
|
367
|
+
Napi::Env env = info.Env();
|
|
368
|
+
|
|
358
369
|
Napi::String partition_id = info[0].As<Napi::String>();
|
|
359
370
|
char *partition_id_cobhan_buffer;
|
|
360
|
-
size_t partition_id_copied_bytes
|
|
361
|
-
NAPI_STRING_TO_CBUFFER(partition_id, partition_id_cobhan_buffer,
|
|
371
|
+
size_t partition_id_copied_bytes;
|
|
372
|
+
NAPI_STRING_TO_CBUFFER(env, partition_id, partition_id_cobhan_buffer,
|
|
362
373
|
partition_id_copied_bytes, "decrypt_string");
|
|
363
374
|
|
|
364
375
|
Napi::String input = info[1].As<Napi::String>();
|
|
365
376
|
char *input_cobhan_buffer;
|
|
366
|
-
size_t input_copied_bytes
|
|
367
|
-
NAPI_STRING_TO_CBUFFER(input, input_cobhan_buffer, input_copied_bytes,
|
|
377
|
+
size_t input_copied_bytes;
|
|
378
|
+
NAPI_STRING_TO_CBUFFER(env, input, input_cobhan_buffer, input_copied_bytes,
|
|
368
379
|
"decrypt_string");
|
|
369
380
|
|
|
370
381
|
char *output_cobhan_buffer;
|
|
371
|
-
|
|
372
|
-
"decrypt_string");
|
|
382
|
+
ALLOCATE_CBUFFER(output_cobhan_buffer, input_copied_bytes, "decrypt_string");
|
|
373
383
|
|
|
374
384
|
char *partition_id_canary_ptr = get_canary_ptr(partition_id_cobhan_buffer);
|
|
375
385
|
if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
|
|
376
386
|
log_error_and_throw(
|
|
377
|
-
|
|
387
|
+
"encrypt_to_json",
|
|
378
388
|
"Failed initial canary check for partition_id_cobhan_buffer");
|
|
379
389
|
}
|
|
380
390
|
char *input_canary_ptr = get_canary_ptr(input_cobhan_buffer);
|
|
381
391
|
if (unlikely(!check_canary_ptr(input_canary_ptr))) {
|
|
382
|
-
log_error_and_throw(
|
|
392
|
+
log_error_and_throw("encrypt_to_json",
|
|
383
393
|
"Failed initial canary check for input_cobhan_buffer");
|
|
384
394
|
}
|
|
385
395
|
char *output_canary_ptr = get_canary_ptr(output_cobhan_buffer);
|
|
386
396
|
if (unlikely(!check_canary_ptr(output_canary_ptr))) {
|
|
387
|
-
log_error_and_throw(
|
|
397
|
+
log_error_and_throw("encrypt_to_json",
|
|
388
398
|
"Failed initial canary check for output_cobhan_buffer");
|
|
389
399
|
}
|
|
390
400
|
|
|
@@ -403,23 +413,23 @@ Napi::String decrypt_string(const Napi::CallbackInfo &info) {
|
|
|
403
413
|
|
|
404
414
|
if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
|
|
405
415
|
log_error_and_throw(
|
|
406
|
-
|
|
416
|
+
"encrypt_to_json",
|
|
407
417
|
"Failed post-call canary check for partition_id_cobhan_buffer");
|
|
408
418
|
}
|
|
409
419
|
if (unlikely(!check_canary_ptr(input_canary_ptr))) {
|
|
410
420
|
log_error_and_throw(
|
|
411
|
-
|
|
421
|
+
"encrypt_to_json",
|
|
412
422
|
"Failed post-call canary check for input_cobhan_buffer");
|
|
413
423
|
}
|
|
414
424
|
if (unlikely(!check_canary_ptr(output_canary_ptr))) {
|
|
415
425
|
log_error_and_throw(
|
|
416
|
-
|
|
426
|
+
"encrypt_to_json",
|
|
417
427
|
"Failed post-call canary check for output_cobhan_buffer");
|
|
418
428
|
}
|
|
419
429
|
|
|
420
430
|
if (unlikely(result < 0)) {
|
|
421
431
|
// TODO: Convert this to a proper error message
|
|
422
|
-
log_error_and_throw(
|
|
432
|
+
log_error_and_throw("decrypt_string", std::to_string(result));
|
|
423
433
|
}
|
|
424
434
|
|
|
425
435
|
Napi::String output = cbuffer_to_nstring(env, output_cobhan_buffer);
|
|
@@ -432,6 +442,8 @@ Napi::String decrypt_string(const Napi::CallbackInfo &info) {
|
|
|
432
442
|
}
|
|
433
443
|
|
|
434
444
|
void shutdown(const Napi::CallbackInfo &info) {
|
|
445
|
+
std::lock_guard<std::mutex> lock(asherah_lock);
|
|
446
|
+
|
|
435
447
|
if (unlikely(verbose_flag)) {
|
|
436
448
|
debug_log("shutdown", "called");
|
|
437
449
|
}
|
|
@@ -451,14 +463,14 @@ void shutdown(const Napi::CallbackInfo &info) {
|
|
|
451
463
|
}
|
|
452
464
|
|
|
453
465
|
void set_max_stack_alloc_item_size(const Napi::CallbackInfo &info) {
|
|
454
|
-
|
|
466
|
+
std::lock_guard<std::mutex> lock(asherah_lock);
|
|
455
467
|
|
|
456
468
|
if (unlikely(verbose_flag)) {
|
|
457
469
|
debug_log("set_max_stack_alloc_item_size", "called");
|
|
458
470
|
}
|
|
459
471
|
|
|
460
472
|
if (unlikely(info.Length() < 1)) {
|
|
461
|
-
log_error_and_throw(
|
|
473
|
+
log_error_and_throw("set_max_stack_alloc_item_size",
|
|
462
474
|
"Wrong number of arguments");
|
|
463
475
|
}
|
|
464
476
|
|
|
@@ -468,20 +480,20 @@ void set_max_stack_alloc_item_size(const Napi::CallbackInfo &info) {
|
|
|
468
480
|
}
|
|
469
481
|
|
|
470
482
|
void set_safety_padding_overhead(const Napi::CallbackInfo &info) {
|
|
471
|
-
|
|
483
|
+
std::lock_guard<std::mutex> lock(asherah_lock);
|
|
472
484
|
|
|
473
485
|
if (unlikely(verbose_flag)) {
|
|
474
486
|
debug_log("set_safety_padding_overhead", "called");
|
|
475
487
|
}
|
|
476
488
|
|
|
477
489
|
if (unlikely(info.Length() < 1)) {
|
|
478
|
-
log_error_and_throw(
|
|
490
|
+
log_error_and_throw("set_safety_padding_overhead",
|
|
479
491
|
"Wrong number of arguments");
|
|
480
492
|
}
|
|
481
493
|
|
|
482
494
|
Napi::Number safety_padding_number = info[0].ToNumber();
|
|
483
495
|
|
|
484
|
-
|
|
496
|
+
set_safety_padding_bytes((size_t)safety_padding_number.Int32Value());
|
|
485
497
|
}
|
|
486
498
|
|
|
487
499
|
Napi::Object Init(Napi::Env env, Napi::Object exports) {
|
package/src/cobhan.cc
ADDED
package/src/cobhan.h
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
#ifndef COBHAN_H
|
|
2
|
+
#define COBHAN_H
|
|
3
|
+
#include "logging.h"
|
|
4
|
+
#include <cstdint>
|
|
5
|
+
#include <stddef.h>
|
|
6
|
+
#include <string>
|
|
7
|
+
|
|
8
|
+
extern size_t safety_padding_bytes;
|
|
9
|
+
|
|
10
|
+
const size_t cobhan_header_size_bytes = 64 / 8;
|
|
11
|
+
const size_t canary_size = sizeof(int32_t) * 2;
|
|
12
|
+
const int32_t canary_constant = 0xdeadbeef;
|
|
13
|
+
|
|
14
|
+
__attribute__((always_inline)) inline void
|
|
15
|
+
set_safety_padding_bytes(size_t new_safety_padding_bytes) {
|
|
16
|
+
safety_padding_bytes = new_safety_padding_bytes;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
__attribute__((always_inline)) inline int32_t
|
|
20
|
+
cbuffer_byte_length(char *cobhan_buffer) {
|
|
21
|
+
return *((int32_t *)cobhan_buffer);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
__attribute__((always_inline)) inline char *
|
|
25
|
+
cbuffer_data_ptr(char *cobhan_buffer) {
|
|
26
|
+
return cobhan_buffer + cobhan_header_size_bytes;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
__attribute__((always_inline)) inline size_t
|
|
30
|
+
calculate_cobhan_buffer_allocation_size(size_t data_len_bytes) {
|
|
31
|
+
return data_len_bytes + cobhan_header_size_bytes +
|
|
32
|
+
1 + // Add one for possible NULL delimiter due to Node string functions
|
|
33
|
+
canary_size // Add space for canary value
|
|
34
|
+
+ safety_padding_bytes; // Add safety padding if configured
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
__attribute__((always_inline)) inline void
|
|
38
|
+
configure_cbuffer(char *cobhan_buffer, size_t length) {
|
|
39
|
+
if (unlikely(verbose_flag)) {
|
|
40
|
+
debug_log("configure_cbuffer", "configure_cbuffer(" +
|
|
41
|
+
format_ptr(cobhan_buffer) + ", " +
|
|
42
|
+
std::to_string(length) + ")");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
*((int32_t *)cobhan_buffer) = length;
|
|
46
|
+
// Reserved for future use
|
|
47
|
+
*((int32_t *)(cobhan_buffer + sizeof(int32_t))) = 0;
|
|
48
|
+
|
|
49
|
+
// Write canary values
|
|
50
|
+
char *data_ptr = cbuffer_data_ptr(cobhan_buffer);
|
|
51
|
+
#ifdef LOG_CANARY_WRITES
|
|
52
|
+
if (unlikely(verbose_flag)) {
|
|
53
|
+
debug_log("configure_cbuffer",
|
|
54
|
+
"Writing first canary at " + format_ptr(data_ptr + length + 1));
|
|
55
|
+
}
|
|
56
|
+
#endif
|
|
57
|
+
|
|
58
|
+
// First canary value is a int32_t 0 which gives us four NULLs
|
|
59
|
+
*((int32_t *)(data_ptr + length + 1)) = 0;
|
|
60
|
+
#ifdef LOG_CANARY_WRITES
|
|
61
|
+
if (unlikely(verbose_flag)) {
|
|
62
|
+
debug_log("configure_cbuffer",
|
|
63
|
+
"Writing second canary at " +
|
|
64
|
+
format_ptr(data_ptr + length + 1 + sizeof(int32_t)));
|
|
65
|
+
}
|
|
66
|
+
#endif
|
|
67
|
+
|
|
68
|
+
// Second canary value is a int32_t 0xdeadbeef
|
|
69
|
+
*((int32_t *)(data_ptr + length + 1 + sizeof(int32_t))) = canary_constant;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
__attribute__((always_inline)) inline char *
|
|
73
|
+
get_canary_ptr(char *cobhan_buffer) {
|
|
74
|
+
int32_t cobhan_buffer_size_bytes = cbuffer_byte_length(cobhan_buffer);
|
|
75
|
+
return cbuffer_data_ptr(cobhan_buffer) + cobhan_buffer_size_bytes + 1;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
__attribute__((always_inline)) inline bool check_canary_ptr(char *canary_ptr) {
|
|
79
|
+
int32_t zero_value = *((int32_t *)(canary_ptr));
|
|
80
|
+
if (zero_value != 0) {
|
|
81
|
+
std::string error_msg =
|
|
82
|
+
"Canary check failed: " + std::to_string(zero_value) + " != 0";
|
|
83
|
+
error_log("canary_check_cbuffer", error_msg);
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
int32_t canary_value = *((int32_t *)(canary_ptr + sizeof(int32_t)));
|
|
87
|
+
if (canary_value != canary_constant) {
|
|
88
|
+
std::string error_msg =
|
|
89
|
+
"Canary check failed: " + std::to_string(canary_value) +
|
|
90
|
+
" != " + std::to_string(canary_constant);
|
|
91
|
+
error_log("canary_check_cbuffer", error_msg);
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
__attribute__((always_inline)) inline std::unique_ptr<char[]>
|
|
98
|
+
heap_allocate_cbuffer(const char *variable_name, size_t size_bytes) {
|
|
99
|
+
size_t cobhan_buffer_allocation_size =
|
|
100
|
+
calculate_cobhan_buffer_allocation_size(size_bytes);
|
|
101
|
+
if (unlikely(verbose_flag)) {
|
|
102
|
+
std::string log_msg =
|
|
103
|
+
"heap_allocate_cbuffer(" + std::to_string(size_bytes) +
|
|
104
|
+
") (heap) cobhan_buffer_allocation_size: " +
|
|
105
|
+
std::to_string(cobhan_buffer_allocation_size) + " for " + variable_name;
|
|
106
|
+
debug_log("allocate_cbuffer", log_msg);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
char *cobhan_buffer = new (std::nothrow) char[cobhan_buffer_allocation_size];
|
|
110
|
+
if (unlikely(cobhan_buffer == nullptr)) {
|
|
111
|
+
std::string error_msg = "new[" +
|
|
112
|
+
std::to_string(cobhan_buffer_allocation_size) +
|
|
113
|
+
"] returned null";
|
|
114
|
+
error_log("allocate_cbuffer", error_msg);
|
|
115
|
+
return nullptr;
|
|
116
|
+
}
|
|
117
|
+
std::unique_ptr<char[]> cobhan_buffer_unique_ptr(cobhan_buffer);
|
|
118
|
+
configure_cbuffer(cobhan_buffer, size_bytes + safety_padding_bytes);
|
|
119
|
+
return cobhan_buffer_unique_ptr;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
#define ALLOCATE_CBUFFER_UNIQUE_PTR(cobhan_buffer, buffer_size, unique_ptr, \
|
|
123
|
+
function_name) \
|
|
124
|
+
do { \
|
|
125
|
+
if (buffer_size < max_stack_alloc_size) { \
|
|
126
|
+
/* If the buffer is small enough, allocate it on the stack */ \
|
|
127
|
+
size_t cobhan_buffer##_cobhan_buffer_allocation_size = \
|
|
128
|
+
calculate_cobhan_buffer_allocation_size(buffer_size); \
|
|
129
|
+
debug_log_alloca(function_name, #cobhan_buffer, \
|
|
130
|
+
cobhan_buffer##_cobhan_buffer_allocation_size); \
|
|
131
|
+
cobhan_buffer = \
|
|
132
|
+
(char *)alloca(cobhan_buffer##_cobhan_buffer_allocation_size); \
|
|
133
|
+
configure_cbuffer(cobhan_buffer, buffer_size); \
|
|
134
|
+
} else { \
|
|
135
|
+
/* Otherwise, allocate it on the heap */ \
|
|
136
|
+
unique_ptr = heap_allocate_cbuffer(#cobhan_buffer, buffer_size); \
|
|
137
|
+
cobhan_buffer = unique_ptr.get(); \
|
|
138
|
+
} \
|
|
139
|
+
if (unlikely(cobhan_buffer == nullptr)) { \
|
|
140
|
+
log_error_and_throw(function_name, \
|
|
141
|
+
"Failed to allocate " #cobhan_buffer); \
|
|
142
|
+
} \
|
|
143
|
+
} while (0);
|
|
144
|
+
|
|
145
|
+
#define ALLOCATE_CBUFFER(cobhan_buffer, buffer_size, function_name) \
|
|
146
|
+
std::unique_ptr<char[]> cobhan_buffer##_unique_ptr; \
|
|
147
|
+
ALLOCATE_CBUFFER_UNIQUE_PTR(cobhan_buffer, buffer_size, \
|
|
148
|
+
cobhan_buffer##_unique_ptr, function_name);
|
|
149
|
+
|
|
150
|
+
#endif
|
|
@@ -1,11 +1,2 @@
|
|
|
1
1
|
#include <stddef.h>
|
|
2
|
-
|
|
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
|
+
__attribute__((used)) size_t est_intermediate_key_overhead = 0;
|
|
@@ -1,26 +1,17 @@
|
|
|
1
1
|
#ifndef COBHAN_NAPI_INTEROP_H
|
|
2
2
|
#define COBHAN_NAPI_INTEROP_H
|
|
3
|
+
#include "cobhan.h"
|
|
3
4
|
#include "hints.h"
|
|
4
5
|
#include "logging.h"
|
|
5
6
|
#include <napi.h>
|
|
6
7
|
#include <string>
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
size_t *get_est_intermediate_key_overhead_ptr();
|
|
10
|
-
size_t *get_safety_padding_bytes_ptr();
|
|
11
|
-
|
|
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();
|
|
9
|
+
extern size_t est_intermediate_key_overhead;
|
|
15
10
|
|
|
16
11
|
const size_t est_encryption_overhead = 48;
|
|
17
12
|
const size_t est_envelope_overhead = 185;
|
|
18
13
|
const double base64_overhead = 1.34;
|
|
19
14
|
|
|
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;
|
|
23
|
-
|
|
24
15
|
std::string napi_status_to_string(napi_status status) {
|
|
25
16
|
switch (status) {
|
|
26
17
|
case napi_ok:
|
|
@@ -72,27 +63,6 @@ std::string napi_status_to_string(napi_status status) {
|
|
|
72
63
|
}
|
|
73
64
|
}
|
|
74
65
|
|
|
75
|
-
__attribute__((always_inline)) inline int32_t
|
|
76
|
-
cbuffer_byte_length(char *cobhan_buffer) {
|
|
77
|
-
return *((int32_t *)cobhan_buffer);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
__attribute__((always_inline)) inline void
|
|
81
|
-
log_error_and_throw(Napi::Env &env, const char *function_name,
|
|
82
|
-
std::string error_msg) {
|
|
83
|
-
error_log(function_name, error_msg);
|
|
84
|
-
Napi::Error::New(env, function_name + (": " + error_msg))
|
|
85
|
-
.ThrowAsJavaScriptException();
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
__attribute__((always_inline)) inline size_t
|
|
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
|
|
94
|
-
}
|
|
95
|
-
|
|
96
66
|
__attribute__((always_inline)) inline size_t
|
|
97
67
|
estimate_asherah_output_size_bytes(size_t data_byte_len,
|
|
98
68
|
size_t partition_byte_len) {
|
|
@@ -100,9 +70,9 @@ estimate_asherah_output_size_bytes(size_t data_byte_len,
|
|
|
100
70
|
double est_data_byte_len =
|
|
101
71
|
(double(data_byte_len + est_encryption_overhead) * base64_overhead) + 1;
|
|
102
72
|
|
|
103
|
-
size_t asherah_output_size_bytes =
|
|
104
|
-
est_envelope_overhead +
|
|
105
|
-
|
|
73
|
+
size_t asherah_output_size_bytes =
|
|
74
|
+
size_t(est_envelope_overhead + est_intermediate_key_overhead +
|
|
75
|
+
partition_byte_len + est_data_byte_len);
|
|
106
76
|
if (unlikely(verbose_flag)) {
|
|
107
77
|
std::string log_msg =
|
|
108
78
|
"estimate_asherah_output_size(" + std::to_string(data_byte_len) + ", " +
|
|
@@ -115,118 +85,6 @@ estimate_asherah_output_size_bytes(size_t data_byte_len,
|
|
|
115
85
|
return asherah_output_size_bytes;
|
|
116
86
|
}
|
|
117
87
|
|
|
118
|
-
__attribute__((always_inline)) inline char *
|
|
119
|
-
cbuffer_data_ptr(char *cobhan_buffer) {
|
|
120
|
-
return cobhan_buffer + cobhan_header_size_bytes;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
__attribute__((always_inline)) inline void configure_cbuffer(char *buffer,
|
|
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
|
-
|
|
131
|
-
*((int32_t *)buffer) = length;
|
|
132
|
-
// Reserved for future use
|
|
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;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
__attribute__((always_inline)) inline std::unique_ptr<char[]>
|
|
183
|
-
heap_allocate_cbuffer(const char *variable_name, size_t size_bytes) {
|
|
184
|
-
size_t cobhan_buffer_allocation_size =
|
|
185
|
-
calculate_cobhan_buffer_allocation_size(size_bytes);
|
|
186
|
-
if (unlikely(verbose_flag)) {
|
|
187
|
-
std::string log_msg =
|
|
188
|
-
"heap_allocate_cbuffer(" + std::to_string(size_bytes) +
|
|
189
|
-
") (heap) cobhan_buffer_allocation_size: " +
|
|
190
|
-
std::to_string(cobhan_buffer_allocation_size) + " for " + variable_name;
|
|
191
|
-
debug_log("allocate_cbuffer", log_msg);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
char *cobhan_buffer = new (std::nothrow) char[cobhan_buffer_allocation_size];
|
|
195
|
-
if (unlikely(cobhan_buffer == nullptr)) {
|
|
196
|
-
std::string error_msg = "new[" +
|
|
197
|
-
std::to_string(cobhan_buffer_allocation_size) +
|
|
198
|
-
"] returned null";
|
|
199
|
-
error_log("allocate_cbuffer", error_msg);
|
|
200
|
-
return nullptr;
|
|
201
|
-
}
|
|
202
|
-
std::unique_ptr<char[]> cobhan_buffer_unique_ptr(cobhan_buffer);
|
|
203
|
-
configure_cbuffer(cobhan_buffer, size_bytes + *safety_padding_bytes_ptr);
|
|
204
|
-
return cobhan_buffer_unique_ptr;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
__attribute__((always_inline)) inline Napi::String
|
|
208
|
-
cbuffer_to_nstring(Napi::Env &env, char *cobhan_buffer) {
|
|
209
|
-
napi_value output;
|
|
210
|
-
|
|
211
|
-
int32_t cobhan_buffer_size_bytes = cbuffer_byte_length(cobhan_buffer);
|
|
212
|
-
if (cobhan_buffer_size_bytes <= 0) {
|
|
213
|
-
log_error_and_throw(env, "cbuffer_to_nstring",
|
|
214
|
-
"Invalid cobhan buffer byte length");
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// Using C function because it allows length delimited input
|
|
218
|
-
napi_status status = napi_create_string_utf8(
|
|
219
|
-
env, cbuffer_data_ptr(cobhan_buffer), cobhan_buffer_size_bytes, &output);
|
|
220
|
-
|
|
221
|
-
if (unlikely(status != napi_ok)) {
|
|
222
|
-
log_error_and_throw(env, "cbuffer_to_nstring",
|
|
223
|
-
"napi_create_string_utf8 failed: " +
|
|
224
|
-
napi_status_to_string(status));
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
return Napi::String(env, output);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
88
|
__attribute__((always_inline)) inline size_t
|
|
231
89
|
nstring_utf8_byte_length(Napi::Env &env, Napi::String &str) {
|
|
232
90
|
napi_status status;
|
|
@@ -234,9 +92,9 @@ nstring_utf8_byte_length(Napi::Env &env, Napi::String &str) {
|
|
|
234
92
|
|
|
235
93
|
status = napi_get_value_string_utf8(env, str, nullptr, 0, &utf8_length);
|
|
236
94
|
if (unlikely(status != napi_ok)) {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
95
|
+
error_log("nstring_utf8_length",
|
|
96
|
+
"napi_get_value_string_utf8 length check failed: " +
|
|
97
|
+
napi_status_to_string(status));
|
|
240
98
|
return (size_t)(-1);
|
|
241
99
|
}
|
|
242
100
|
|
|
@@ -250,24 +108,21 @@ copy_nstring_to_cbuffer(Napi::Env &env, Napi::String &str,
|
|
|
250
108
|
|
|
251
109
|
size_t cobhan_buffer_size_bytes = cbuffer_byte_length(cobhan_buffer);
|
|
252
110
|
if (unlikely(cobhan_buffer_size_bytes <= 0)) {
|
|
253
|
-
|
|
254
|
-
"Invalid cobhan buffer byte length");
|
|
111
|
+
error_log("copy_nstring_to_cbuffer", "Invalid cobhan buffer byte length");
|
|
255
112
|
return nullptr;
|
|
256
113
|
}
|
|
257
114
|
|
|
258
115
|
if (cobhan_buffer_size_bytes < str_utf8_byte_length) {
|
|
259
|
-
|
|
260
|
-
"String too large for cobhan buffer");
|
|
116
|
+
error_log("copy_nstring_to_cbuffer", "String too large for cobhan buffer");
|
|
261
117
|
return nullptr;
|
|
262
118
|
}
|
|
263
119
|
|
|
264
120
|
if (unlikely(verbose_flag)) {
|
|
265
121
|
debug_log("copy_nstring_to_cbuffer",
|
|
266
122
|
"Copying " + std::to_string(str_utf8_byte_length) + " bytes to " +
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
str_utf8_byte_length)));
|
|
123
|
+
format_ptr(cbuffer_data_ptr(cobhan_buffer)) + " - " +
|
|
124
|
+
format_ptr((cbuffer_data_ptr(cobhan_buffer) +
|
|
125
|
+
str_utf8_byte_length)));
|
|
271
126
|
}
|
|
272
127
|
|
|
273
128
|
napi_status status;
|
|
@@ -278,17 +133,17 @@ copy_nstring_to_cbuffer(Napi::Env &env, Napi::String &str,
|
|
|
278
133
|
status = napi_get_value_string_utf8(env, str, cbuffer_data_ptr(cobhan_buffer),
|
|
279
134
|
str_utf8_byte_length + 1, &copied_bytes);
|
|
280
135
|
if (unlikely(status != napi_ok)) {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
136
|
+
error_log("copy_nstring_to_cbuffer",
|
|
137
|
+
"Napi utf8 string conversion failure: " +
|
|
138
|
+
napi_status_to_string(status));
|
|
284
139
|
return nullptr;
|
|
285
140
|
}
|
|
286
141
|
|
|
287
142
|
if (unlikely(copied_bytes != str_utf8_byte_length)) {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
143
|
+
error_log("copy_nstring_to_cbuffer",
|
|
144
|
+
"Did not copy expected number of bytes " +
|
|
145
|
+
std::to_string(str_utf8_byte_length) + " copied " +
|
|
146
|
+
std::to_string(copied_bytes));
|
|
292
147
|
return nullptr;
|
|
293
148
|
}
|
|
294
149
|
|
|
@@ -299,34 +154,34 @@ copy_nstring_to_cbuffer(Napi::Env &env, Napi::String &str,
|
|
|
299
154
|
return cobhan_buffer;
|
|
300
155
|
}
|
|
301
156
|
|
|
302
|
-
__attribute__((always_inline)) inline
|
|
303
|
-
|
|
304
|
-
|
|
157
|
+
__attribute__((always_inline)) inline Napi::String
|
|
158
|
+
cbuffer_to_nstring(Napi::Env &env, char *cobhan_buffer) {
|
|
159
|
+
napi_value output;
|
|
305
160
|
|
|
306
161
|
int32_t cobhan_buffer_size_bytes = cbuffer_byte_length(cobhan_buffer);
|
|
307
|
-
if (
|
|
308
|
-
log_error_and_throw(
|
|
162
|
+
if (cobhan_buffer_size_bytes <= 0) {
|
|
163
|
+
log_error_and_throw("cbuffer_to_nstring",
|
|
309
164
|
"Invalid cobhan buffer byte length");
|
|
310
|
-
return nullptr;
|
|
311
165
|
}
|
|
312
166
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
167
|
+
// Using C function because it allows length delimited input
|
|
168
|
+
napi_status status = napi_create_string_utf8(
|
|
169
|
+
env, cbuffer_data_ptr(cobhan_buffer), cobhan_buffer_size_bytes, &output);
|
|
170
|
+
|
|
171
|
+
if (unlikely(status != napi_ok)) {
|
|
172
|
+
log_error_and_throw("cbuffer_to_nstring",
|
|
173
|
+
"napi_create_string_utf8 failed: " +
|
|
174
|
+
napi_status_to_string(status));
|
|
319
175
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
return cobhan_buffer;
|
|
176
|
+
|
|
177
|
+
return Napi::String(env, output);
|
|
323
178
|
}
|
|
324
179
|
|
|
325
180
|
__attribute__((always_inline)) inline Napi::Buffer<unsigned char>
|
|
326
181
|
cbuffer_to_nbuffer(Napi::Env &env, char *cobhan_buffer) {
|
|
327
182
|
int32_t cobhan_buffer_byte_length = cbuffer_byte_length(cobhan_buffer);
|
|
328
183
|
if (unlikely(cobhan_buffer_byte_length <= 0)) {
|
|
329
|
-
log_error_and_throw(
|
|
184
|
+
log_error_and_throw("cbuffer_to_nbuffer",
|
|
330
185
|
"Invalid cobhan buffer byte length");
|
|
331
186
|
}
|
|
332
187
|
|
|
@@ -337,7 +192,7 @@ cbuffer_to_nbuffer(Napi::Env &env, char *cobhan_buffer) {
|
|
|
337
192
|
}
|
|
338
193
|
|
|
339
194
|
if (unlikely(cobhan_buffer_byte_length <= 0)) {
|
|
340
|
-
log_error_and_throw(
|
|
195
|
+
log_error_and_throw("cbuffer_to_nbuffer",
|
|
341
196
|
"Invalid cobhan buffer byte length");
|
|
342
197
|
}
|
|
343
198
|
|
|
@@ -353,115 +208,75 @@ cbuffer_to_nbuffer(Napi::Env &env, char *cobhan_buffer) {
|
|
|
353
208
|
return nbuffer;
|
|
354
209
|
}
|
|
355
210
|
|
|
211
|
+
__attribute__((always_inline)) inline char *
|
|
212
|
+
copy_nbuffer_to_cbuffer(Napi::Env &env, Napi::Buffer<unsigned char> &nbuffer,
|
|
213
|
+
char *cobhan_buffer) {
|
|
214
|
+
|
|
215
|
+
int32_t cobhan_buffer_size_bytes = cbuffer_byte_length(cobhan_buffer);
|
|
216
|
+
if (unlikely(cobhan_buffer_size_bytes <= 0)) {
|
|
217
|
+
error_log("copy_nbuffer_to_cbuffer", "Invalid cobhan buffer byte length");
|
|
218
|
+
return nullptr;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
size_t nbuffer_byte_length = nbuffer.ByteLength();
|
|
222
|
+
if (nbuffer_byte_length > INT32_MAX ||
|
|
223
|
+
cobhan_buffer_size_bytes < (int32_t)nbuffer_byte_length) {
|
|
224
|
+
error_log("copy_nbuffer_to_cbuffer", "Buffer too large for cobhan buffer");
|
|
225
|
+
return nullptr;
|
|
226
|
+
}
|
|
227
|
+
memcpy(cbuffer_data_ptr(cobhan_buffer), nbuffer.Data(), nbuffer_byte_length);
|
|
228
|
+
configure_cbuffer(cobhan_buffer, nbuffer_byte_length);
|
|
229
|
+
return cobhan_buffer;
|
|
230
|
+
}
|
|
231
|
+
|
|
356
232
|
// These are macros due to the use of alloca()
|
|
357
233
|
|
|
358
|
-
#define NAPI_STRING_TO_CBUFFER(napi_string, cobhan_buffer, bytes_copied,
|
|
234
|
+
#define NAPI_STRING_TO_CBUFFER(env, napi_string, cobhan_buffer, bytes_copied, \
|
|
359
235
|
function_name) \
|
|
360
|
-
std::unique_ptr<char[]> napi_string##
|
|
236
|
+
std::unique_ptr<char[]> napi_string##_unique_ptr; \
|
|
361
237
|
do { \
|
|
362
238
|
/* Determine size */ \
|
|
363
239
|
size_t napi_string##_utf8_byte_length = \
|
|
364
240
|
nstring_utf8_byte_length(env, napi_string); \
|
|
365
241
|
if (unlikely(napi_string##_utf8_byte_length == (size_t)(-1))) { \
|
|
366
|
-
log_error_and_throw(
|
|
242
|
+
log_error_and_throw(function_name, \
|
|
367
243
|
"Failed to get " #napi_string " utf8 length"); \
|
|
368
244
|
} \
|
|
369
245
|
if (unlikely(napi_string##_utf8_byte_length == 0)) { \
|
|
370
|
-
log_error_and_throw(
|
|
246
|
+
log_error_and_throw(function_name, #napi_string " is empty"); \
|
|
371
247
|
} \
|
|
372
248
|
/* Allocate */ \
|
|
373
|
-
|
|
374
|
-
|
|
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
|
-
} \
|
|
249
|
+
ALLOCATE_CBUFFER_UNIQUE_PTR(cobhan_buffer, napi_string##_utf8_byte_length, \
|
|
250
|
+
napi_string##_unique_ptr, function_name); \
|
|
394
251
|
/* Copy */ \
|
|
395
252
|
cobhan_buffer = copy_nstring_to_cbuffer(env, napi_string, \
|
|
396
253
|
napi_string##_utf8_byte_length, \
|
|
397
254
|
cobhan_buffer, &bytes_copied); \
|
|
398
255
|
if (unlikely(cobhan_buffer == nullptr)) { \
|
|
399
|
-
log_error_and_throw(
|
|
256
|
+
log_error_and_throw(function_name, \
|
|
400
257
|
"Failed to copy " #napi_string " to cobhan buffer"); \
|
|
401
258
|
} \
|
|
402
259
|
} while (0);
|
|
403
260
|
|
|
404
|
-
#define NAPI_BUFFER_TO_CBUFFER(napi_buffer, cobhan_buffer, bytes_copied,
|
|
261
|
+
#define NAPI_BUFFER_TO_CBUFFER(env, napi_buffer, cobhan_buffer, bytes_copied, \
|
|
405
262
|
function_name) \
|
|
406
263
|
std::unique_ptr<char[]> napi_buffer##_unique_ptr; \
|
|
407
264
|
do { \
|
|
408
265
|
/* Determine size */ \
|
|
409
266
|
size_t napi_buffer##_byte_length = napi_buffer.ByteLength(); \
|
|
410
267
|
if (unlikely(napi_buffer##_byte_length == 0)) { \
|
|
411
|
-
log_error_and_throw(
|
|
268
|
+
log_error_and_throw(function_name, #napi_buffer " is empty"); \
|
|
412
269
|
} \
|
|
413
270
|
/* Allocate */ \
|
|
414
|
-
|
|
415
|
-
|
|
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
|
-
} \
|
|
271
|
+
ALLOCATE_CBUFFER_UNIQUE_PTR(cobhan_buffer, napi_buffer##_byte_length, \
|
|
272
|
+
napi_buffer##_unique_ptr, function_name); \
|
|
434
273
|
/* Copy */ \
|
|
435
274
|
cobhan_buffer = copy_nbuffer_to_cbuffer(env, napi_buffer, cobhan_buffer); \
|
|
436
275
|
if (unlikely(cobhan_buffer == nullptr)) { \
|
|
437
|
-
log_error_and_throw(
|
|
276
|
+
log_error_and_throw(function_name, \
|
|
438
277
|
"Failed to copy " #napi_buffer " to cobhan buffer"); \
|
|
439
278
|
} \
|
|
440
279
|
bytes_copied = napi_buffer##_byte_length; \
|
|
441
280
|
} while (0);
|
|
442
281
|
|
|
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
|
-
|
|
467
282
|
#endif
|
package/src/logging.cc
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#include <cstdint>
|
|
2
|
-
int32_t verbose_flag = 0;
|
|
2
|
+
__attribute__((used)) int32_t verbose_flag = 0;
|
package/src/logging.h
CHANGED
|
@@ -2,11 +2,22 @@
|
|
|
2
2
|
#define LOGGING_H
|
|
3
3
|
#include "hints.h"
|
|
4
4
|
#include <cstdint>
|
|
5
|
-
#include <
|
|
5
|
+
#include <iomanip>
|
|
6
6
|
#include <iostream>
|
|
7
|
+
#include <sstream>
|
|
8
|
+
#include <string>
|
|
7
9
|
|
|
8
10
|
extern int32_t verbose_flag;
|
|
9
11
|
|
|
12
|
+
__attribute__((always_inline)) inline void debug_log(const char *function_name,
|
|
13
|
+
const char *message) {
|
|
14
|
+
if (unlikely(verbose_flag)) {
|
|
15
|
+
std::cerr << "asherah-node: [DEBUG] " << function_name << ": " << message
|
|
16
|
+
<< std::endl
|
|
17
|
+
<< std::flush;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
10
21
|
__attribute__((always_inline)) inline void debug_log(const char *function_name,
|
|
11
22
|
std::string message) {
|
|
12
23
|
if (unlikely(verbose_flag)) {
|
|
@@ -27,6 +38,15 @@ debug_log_alloca(const char *function_name, const char *variable_name,
|
|
|
27
38
|
}
|
|
28
39
|
}
|
|
29
40
|
|
|
41
|
+
__attribute__((always_inline)) inline void error_log(const char *function_name,
|
|
42
|
+
const char *message) {
|
|
43
|
+
if (unlikely(verbose_flag)) {
|
|
44
|
+
std::cerr << "asherah-node: [ERROR] " << function_name << ": " << message
|
|
45
|
+
<< std::endl
|
|
46
|
+
<< std::flush;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
30
50
|
__attribute__((always_inline)) inline void error_log(const char *function_name,
|
|
31
51
|
std::string message) {
|
|
32
52
|
if (unlikely(verbose_flag)) {
|
|
@@ -36,4 +56,16 @@ __attribute__((always_inline)) inline void error_log(const char *function_name,
|
|
|
36
56
|
}
|
|
37
57
|
}
|
|
38
58
|
|
|
59
|
+
__attribute__((always_inline)) inline std::string format_ptr(char *ptr) {
|
|
60
|
+
std::ostringstream ss;
|
|
61
|
+
ss << "0x" << std::hex << (intptr_t)ptr;
|
|
62
|
+
return ss.str();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
__attribute__((always_inline, noreturn)) inline void
|
|
66
|
+
log_error_and_throw(const char *function_name, std::string error_msg) {
|
|
67
|
+
error_log(function_name, error_msg);
|
|
68
|
+
throw new std::runtime_error(function_name + (": " + error_msg));
|
|
69
|
+
}
|
|
70
|
+
|
|
39
71
|
#endif
|