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 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.17",
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
- est_intermediate_key_overhead =
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
- safety_padding_bytes = (size_t)safety_padding_number.Int32Value();
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 size_t est_intermediate_key_overhead;
9
- extern size_t safety_padding_bytes;
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 + safety_padding_bytes +
85
- 1; // Add one for possible NULL delimiter due to Node string functions
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
- size_t(est_envelope_overhead + est_intermediate_key_overhead +
97
- partition_byte_len + est_data_byte_len + safety_padding_bytes);
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 + 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
 
@@ -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