asherah 1.3.17 → 1.3.19
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 +1 -1
- package/package.json +2 -2
- package/src/asherah.cc +89 -2
- package/src/cobhan_napi_interop.cc +10 -2
- package/src/cobhan_napi_interop.h +86 -9
package/binding.gyp
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
'-O3'
|
|
16
16
|
],
|
|
17
17
|
},
|
|
18
|
-
'defines': [ 'NAPI_CPP_EXCEPTIONS', 'NODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS', 'NODE_ADDON_API_DISABLE_DEPRECATED' ],
|
|
18
|
+
'defines': [ 'NAPI_CPP_EXCEPTIONS', 'NODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS', 'NODE_ADDON_API_DISABLE_DEPRECATED', 'NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED' ],
|
|
19
19
|
'sources': [
|
|
20
20
|
'lib/libasherah.h',
|
|
21
21
|
'src/asherah.cc',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "asherah",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.19",
|
|
4
4
|
"description": "Asherah envelope encryption and key rotation library",
|
|
5
5
|
"exports": {
|
|
6
6
|
"node-addons": "./dist/asherah.node"
|
|
@@ -62,6 +62,6 @@
|
|
|
62
62
|
"types": "dist/asherah.d.ts",
|
|
63
63
|
"dependencies": {
|
|
64
64
|
"cobhan": "^1.0.37",
|
|
65
|
-
"node-addon-api": "
|
|
65
|
+
"node-addon-api": "7.0.0"
|
|
66
66
|
}
|
|
67
67
|
}
|
package/src/asherah.cc
CHANGED
|
@@ -44,7 +44,7 @@ void setup(const Napi::CallbackInfo &info) {
|
|
|
44
44
|
Napi::String product_id = config_json.Get("ProductID").As<Napi::String>();
|
|
45
45
|
Napi::String service_name = config_json.Get("ServiceName").As<Napi::String>();
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
*est_intermediate_key_overhead_ptr =
|
|
48
48
|
product_id.Utf8Value().length() + service_name.Utf8Value().length();
|
|
49
49
|
|
|
50
50
|
Napi::Value verbose = config_json.Get("Verbose");
|
|
@@ -149,6 +149,22 @@ Napi::Value encrypt_to_json(Napi::Env &env, size_t partition_bytes,
|
|
|
149
149
|
"Failed to allocate cobhan output buffer");
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
char *partition_id_canary_ptr = get_canary_ptr(partition_id_cobhan_buffer);
|
|
153
|
+
if(!check_canary_ptr(partition_id_canary_ptr)) {
|
|
154
|
+
return log_error_and_throw(env, "encrypt_to_json",
|
|
155
|
+
"Failed initial canary check for partition_id_cobhan_buffer");
|
|
156
|
+
}
|
|
157
|
+
char *input_canary_ptr = get_canary_ptr(input_cobhan_buffer);
|
|
158
|
+
if(!check_canary_ptr(input_canary_ptr)) {
|
|
159
|
+
return log_error_and_throw(env, "encrypt_to_json",
|
|
160
|
+
"Failed initial canary check for input_cobhan_buffer");
|
|
161
|
+
}
|
|
162
|
+
char *output_canary_ptr = get_canary_ptr(output_cobhan_buffer);
|
|
163
|
+
if(!check_canary_ptr(output_canary_ptr)) {
|
|
164
|
+
return log_error_and_throw(env, "encrypt_to_json",
|
|
165
|
+
"Failed initial canary check for output_cobhan_buffer");
|
|
166
|
+
}
|
|
167
|
+
|
|
152
168
|
if (unlikely(verbose_flag)) {
|
|
153
169
|
debug_log("encrypt_to_json", "Calling asherah-cobhan EncryptToJson");
|
|
154
170
|
}
|
|
@@ -162,6 +178,19 @@ Napi::Value encrypt_to_json(Napi::Env &env, size_t partition_bytes,
|
|
|
162
178
|
debug_log("encrypt_to_json", "Returning from asherah-cobhan EncryptToJson");
|
|
163
179
|
}
|
|
164
180
|
|
|
181
|
+
if(!check_canary_ptr(partition_id_canary_ptr)) {
|
|
182
|
+
return log_error_and_throw(env, "encrypt_to_json",
|
|
183
|
+
"Failed post-call canary check for partition_id_cobhan_buffer");
|
|
184
|
+
}
|
|
185
|
+
if(!check_canary_ptr(input_canary_ptr)) {
|
|
186
|
+
return log_error_and_throw(env, "encrypt_to_json",
|
|
187
|
+
"Failed post-call canary check for input_cobhan_buffer");
|
|
188
|
+
}
|
|
189
|
+
if(!check_canary_ptr(output_canary_ptr)) {
|
|
190
|
+
return log_error_and_throw(env, "encrypt_to_json",
|
|
191
|
+
"Failed post-call canary check for output_cobhan_buffer");
|
|
192
|
+
}
|
|
193
|
+
|
|
165
194
|
if (unlikely(result < 0)) {
|
|
166
195
|
// TODO: Convert this to a proper error message
|
|
167
196
|
return log_error_and_throw(env, "encrypt_to_json", std::to_string(result));
|
|
@@ -537,6 +566,22 @@ Napi::Value decrypt(const Napi::CallbackInfo &info) {
|
|
|
537
566
|
"Failed to allocate cobhan output buffer");
|
|
538
567
|
}
|
|
539
568
|
|
|
569
|
+
char *partition_id_canary_ptr = get_canary_ptr(partition_id_cobhan_buffer);
|
|
570
|
+
if(!check_canary_ptr(partition_id_canary_ptr)) {
|
|
571
|
+
return log_error_and_throw(env, "encrypt_to_json",
|
|
572
|
+
"Failed initial canary check for partition_id_cobhan_buffer");
|
|
573
|
+
}
|
|
574
|
+
char *input_canary_ptr = get_canary_ptr(input_cobhan_buffer);
|
|
575
|
+
if(!check_canary_ptr(input_canary_ptr)) {
|
|
576
|
+
return log_error_and_throw(env, "encrypt_to_json",
|
|
577
|
+
"Failed initial canary check for input_cobhan_buffer");
|
|
578
|
+
}
|
|
579
|
+
char *output_canary_ptr = get_canary_ptr(output_cobhan_buffer);
|
|
580
|
+
if(!check_canary_ptr(output_canary_ptr)) {
|
|
581
|
+
return log_error_and_throw(env, "encrypt_to_json",
|
|
582
|
+
"Failed initial canary check for output_cobhan_buffer");
|
|
583
|
+
}
|
|
584
|
+
|
|
540
585
|
if (unlikely(verbose_flag)) {
|
|
541
586
|
debug_log("decrypt", "Calling asherah-cobhan DecryptFromJson");
|
|
542
587
|
}
|
|
@@ -550,6 +595,19 @@ Napi::Value decrypt(const Napi::CallbackInfo &info) {
|
|
|
550
595
|
debug_log("decrypt", "Returned from asherah-cobhan DecryptFromJson");
|
|
551
596
|
}
|
|
552
597
|
|
|
598
|
+
if(!check_canary_ptr(partition_id_canary_ptr)) {
|
|
599
|
+
return log_error_and_throw(env, "encrypt_to_json",
|
|
600
|
+
"Failed post-call canary check for partition_id_cobhan_buffer");
|
|
601
|
+
}
|
|
602
|
+
if(!check_canary_ptr(input_canary_ptr)) {
|
|
603
|
+
return log_error_and_throw(env, "encrypt_to_json",
|
|
604
|
+
"Failed post-call canary check for input_cobhan_buffer");
|
|
605
|
+
}
|
|
606
|
+
if(!check_canary_ptr(output_canary_ptr)) {
|
|
607
|
+
return log_error_and_throw(env, "encrypt_to_json",
|
|
608
|
+
"Failed post-call canary check for output_cobhan_buffer");
|
|
609
|
+
}
|
|
610
|
+
|
|
553
611
|
if (unlikely(result < 0)) {
|
|
554
612
|
// TODO: Convert this to a proper error message
|
|
555
613
|
return log_error_and_throw(env, "decrypt", std::to_string(result));
|
|
@@ -694,6 +752,22 @@ Napi::Value decrypt_string(const Napi::CallbackInfo &info) {
|
|
|
694
752
|
"Failed to allocate cobhan output buffer");
|
|
695
753
|
}
|
|
696
754
|
|
|
755
|
+
char *partition_id_canary_ptr = get_canary_ptr(partition_id_cobhan_buffer);
|
|
756
|
+
if(!check_canary_ptr(partition_id_canary_ptr)) {
|
|
757
|
+
return log_error_and_throw(env, "encrypt_to_json",
|
|
758
|
+
"Failed initial canary check for partition_id_cobhan_buffer");
|
|
759
|
+
}
|
|
760
|
+
char *input_canary_ptr = get_canary_ptr(input_cobhan_buffer);
|
|
761
|
+
if(!check_canary_ptr(input_canary_ptr)) {
|
|
762
|
+
return log_error_and_throw(env, "encrypt_to_json",
|
|
763
|
+
"Failed initial canary check for input_cobhan_buffer");
|
|
764
|
+
}
|
|
765
|
+
char *output_canary_ptr = get_canary_ptr(output_cobhan_buffer);
|
|
766
|
+
if(!check_canary_ptr(output_canary_ptr)) {
|
|
767
|
+
return log_error_and_throw(env, "encrypt_to_json",
|
|
768
|
+
"Failed initial canary check for output_cobhan_buffer");
|
|
769
|
+
}
|
|
770
|
+
|
|
697
771
|
if (unlikely(verbose_flag)) {
|
|
698
772
|
debug_log("decrypt_string", "Calling asherah-cobhan DecryptFromJson");
|
|
699
773
|
}
|
|
@@ -707,6 +781,19 @@ Napi::Value decrypt_string(const Napi::CallbackInfo &info) {
|
|
|
707
781
|
debug_log("decrypt_string", "Returned from asherah-cobhan DecryptFromJson");
|
|
708
782
|
}
|
|
709
783
|
|
|
784
|
+
if(!check_canary_ptr(partition_id_canary_ptr)) {
|
|
785
|
+
return log_error_and_throw(env, "encrypt_to_json",
|
|
786
|
+
"Failed post-call canary check for partition_id_cobhan_buffer");
|
|
787
|
+
}
|
|
788
|
+
if(!check_canary_ptr(input_canary_ptr)) {
|
|
789
|
+
return log_error_and_throw(env, "encrypt_to_json",
|
|
790
|
+
"Failed post-call canary check for input_cobhan_buffer");
|
|
791
|
+
}
|
|
792
|
+
if(!check_canary_ptr(output_canary_ptr)) {
|
|
793
|
+
return log_error_and_throw(env, "encrypt_to_json",
|
|
794
|
+
"Failed post-call canary check for output_cobhan_buffer");
|
|
795
|
+
}
|
|
796
|
+
|
|
710
797
|
if (unlikely(result < 0)) {
|
|
711
798
|
// TODO: Convert this to a proper error message
|
|
712
799
|
return log_error_and_throw(env, "decrypt_string", std::to_string(result));
|
|
@@ -773,7 +860,7 @@ void set_safety_padding_overhead(const Napi::CallbackInfo &info) {
|
|
|
773
860
|
|
|
774
861
|
Napi::Number safety_padding_number = info[0].ToNumber();
|
|
775
862
|
|
|
776
|
-
|
|
863
|
+
*safety_padding_bytes_ptr = (size_t)safety_padding_number.Int32Value();
|
|
777
864
|
}
|
|
778
865
|
|
|
779
866
|
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
7
|
|
|
8
|
-
extern
|
|
9
|
-
|
|
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();
|
|
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();
|
|
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) {
|
|
@@ -81,8 +88,10 @@ log_error_and_throw(Napi::Env &env, const char *function_name,
|
|
|
81
88
|
|
|
82
89
|
__attribute__((always_inline)) inline size_t
|
|
83
90
|
calculate_cobhan_buffer_size_bytes(size_t data_len_bytes) {
|
|
84
|
-
return data_len_bytes + cobhan_header_size_bytes +
|
|
85
|
-
1
|
|
91
|
+
return data_len_bytes + cobhan_header_size_bytes +
|
|
92
|
+
1 + // Add one for possible NULL delimiter due to Node string functions
|
|
93
|
+
canary_size // Add space for canary value
|
|
94
|
+
+ *safety_padding_bytes_ptr; // Add safety padding if configured
|
|
86
95
|
}
|
|
87
96
|
|
|
88
97
|
__attribute__((always_inline)) inline size_t
|
|
@@ -92,9 +101,9 @@ estimate_asherah_output_size_bytes(size_t data_byte_len,
|
|
|
92
101
|
double est_data_byte_len =
|
|
93
102
|
(double(data_byte_len + est_encryption_overhead) * base64_overhead) + 1;
|
|
94
103
|
|
|
95
|
-
size_t asherah_output_size_bytes =
|
|
96
|
-
|
|
97
|
-
|
|
104
|
+
size_t asherah_output_size_bytes = size_t(
|
|
105
|
+
est_envelope_overhead + *est_intermediate_key_overhead_ptr +
|
|
106
|
+
partition_byte_len + est_data_byte_len + *safety_padding_bytes_ptr);
|
|
98
107
|
if (unlikely(verbose_flag)) {
|
|
99
108
|
std::string log_msg =
|
|
100
109
|
"estimate_asherah_output_size(" + std::to_string(data_byte_len) + ", " +
|
|
@@ -107,11 +116,68 @@ estimate_asherah_output_size_bytes(size_t data_byte_len,
|
|
|
107
116
|
return asherah_output_size_bytes;
|
|
108
117
|
}
|
|
109
118
|
|
|
119
|
+
__attribute__((always_inline)) inline char* 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(
|
|
148
|
+
"configure_cbuffer",
|
|
149
|
+
"Writing second canary at " +
|
|
150
|
+
std::to_string((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
|
|
164
|
+
check_canary_ptr(char *canary_ptr) {
|
|
165
|
+
int32_t zero_value = *((int32_t *)(canary_ptr));
|
|
166
|
+
if (zero_value != 0) {
|
|
167
|
+
std::string error_msg =
|
|
168
|
+
"Canary check failed: " + std::to_string(zero_value) + " != 0";
|
|
169
|
+
error_log("canary_check_cbuffer", error_msg);
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
int32_t canary_value = *((int32_t *)(canary_ptr + sizeof(int32_t)));
|
|
173
|
+
if (canary_value != canary_constant) {
|
|
174
|
+
std::string error_msg =
|
|
175
|
+
"Canary check failed: " + std::to_string(canary_value) +
|
|
176
|
+
" != " + std::to_string(canary_constant);
|
|
177
|
+
error_log("canary_check_cbuffer", error_msg);
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
return true;
|
|
115
181
|
}
|
|
116
182
|
|
|
117
183
|
__attribute__((always_inline)) inline std::unique_ptr<char[]>
|
|
@@ -134,7 +200,7 @@ heap_allocate_cbuffer(const char *variable_name, size_t size_bytes) {
|
|
|
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 +
|
|
203
|
+
configure_cbuffer(cobhan_buffer, size_bytes + *safety_padding_bytes_ptr);
|
|
138
204
|
return cobhan_buffer_unique_ptr;
|
|
139
205
|
}
|
|
140
206
|
|
|
@@ -196,6 +262,17 @@ copy_nstring_to_cbuffer(Napi::Env &env, Napi::String &str,
|
|
|
196
262
|
return nullptr;
|
|
197
263
|
}
|
|
198
264
|
|
|
265
|
+
if (unlikely(verbose_flag)) {
|
|
266
|
+
debug_log("copy_nstring_to_cbuffer",
|
|
267
|
+
"Copying " + std::to_string(str_utf8_byte_length) + " bytes to " +
|
|
268
|
+
std::to_string(
|
|
269
|
+
(intptr_t)(cobhan_buffer + cobhan_header_size_bytes)) +
|
|
270
|
+
"-" +
|
|
271
|
+
std::to_string((intptr_t)(cobhan_buffer +
|
|
272
|
+
cobhan_header_size_bytes +
|
|
273
|
+
str_utf8_byte_length)));
|
|
274
|
+
}
|
|
275
|
+
|
|
199
276
|
napi_status status;
|
|
200
277
|
size_t copied_bytes;
|
|
201
278
|
// NOTE: This implementation relies on the additional byte that is reserved
|