@electerm/ssh2 1.5.0 → 1.11.0

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/install.js CHANGED
@@ -2,19 +2,26 @@
2
2
 
3
3
  const { spawnSync } = require('child_process');
4
4
 
5
+ const forceFailOnNonZero = (process.env.CI_CHECK_FAIL === 'ssh2');
6
+
5
7
  // Attempt to build the bundled optional binding
6
- const result = spawnSync('node-gyp', [
8
+ const args = [
7
9
  `--target=${process.version}`,
8
- 'rebuild'
9
- ], {
10
+ `--real_openssl_major=${/^\d+/.exec(process.versions.openssl)[0]}`,
11
+ 'rebuild',
12
+ ];
13
+ const result = spawnSync('node-gyp', args, {
10
14
  cwd: 'lib/protocol/crypto',
11
15
  encoding: 'utf8',
12
16
  shell: true,
13
17
  stdio: 'inherit',
14
18
  windowsHide: true,
15
19
  });
16
- if (result.error || result.status !== 0)
20
+ if (result.error || result.status !== 0) {
17
21
  console.log('Failed to build optional crypto binding');
18
- else
22
+ if (forceFailOnNonZero)
23
+ process.exit(1);
24
+ } else {
19
25
  console.log('Succeeded in building optional crypto binding');
26
+ }
20
27
  process.exit(0);
package/lib/Channel.js CHANGED
@@ -214,6 +214,7 @@ class Channel extends DuplexStream {
214
214
  destroy() {
215
215
  this.end();
216
216
  this.close();
217
+ return this;
217
218
  }
218
219
 
219
220
  // Session type-specific methods =============================================
@@ -1596,6 +1596,91 @@ class SFTP extends EventEmitter {
1596
1596
  this._debug(`SFTP: Outbound: ${status} expand-path@openssh.com`);
1597
1597
  }
1598
1598
  }
1599
+ ext_copy_data(srcHandle, srcOffset, len, dstHandle, dstOffset, cb) {
1600
+ if (this.server)
1601
+ throw new Error('Client-only method called in server mode');
1602
+
1603
+ const ext = this._extensions['copy-data'];
1604
+ if (ext !== '1')
1605
+ throw new Error('Server does not support this extended request');
1606
+
1607
+ if (!Buffer.isBuffer(srcHandle))
1608
+ throw new Error('Source handle is not a Buffer');
1609
+
1610
+ if (!Buffer.isBuffer(dstHandle))
1611
+ throw new Error('Destination handle is not a Buffer');
1612
+
1613
+ /*
1614
+ uint32 id
1615
+ string "copy-data"
1616
+ string read-from-handle
1617
+ uint64 read-from-offset
1618
+ uint64 read-data-length
1619
+ string write-to-handle
1620
+ uint64 write-to-offset
1621
+ */
1622
+ let p = 0;
1623
+ const buf = Buffer.allocUnsafe(
1624
+ 4 + 1
1625
+ + 4
1626
+ + 4 + 9
1627
+ + 4 + srcHandle.length
1628
+ + 8
1629
+ + 8
1630
+ + 4 + dstHandle.length
1631
+ + 8
1632
+ );
1633
+
1634
+ writeUInt32BE(buf, buf.length - 4, p);
1635
+ p += 4;
1636
+
1637
+ buf[p] = REQUEST.EXTENDED;
1638
+ ++p;
1639
+
1640
+ const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID;
1641
+ writeUInt32BE(buf, reqid, p);
1642
+ p += 4;
1643
+
1644
+ writeUInt32BE(buf, 9, p);
1645
+ p += 4;
1646
+ buf.utf8Write('copy-data', p, 9);
1647
+ p += 9;
1648
+
1649
+ writeUInt32BE(buf, srcHandle.length, p);
1650
+ p += 4;
1651
+ buf.set(srcHandle, p);
1652
+ p += srcHandle.length;
1653
+
1654
+ for (let i = 7; i >= 0; --i) {
1655
+ buf[p + i] = srcOffset & 0xFF;
1656
+ srcOffset /= 256;
1657
+ }
1658
+ p += 8;
1659
+
1660
+ for (let i = 7; i >= 0; --i) {
1661
+ buf[p + i] = len & 0xFF;
1662
+ len /= 256;
1663
+ }
1664
+ p += 8;
1665
+
1666
+ writeUInt32BE(buf, dstHandle.length, p);
1667
+ p += 4;
1668
+ buf.set(dstHandle, p);
1669
+ p += dstHandle.length;
1670
+
1671
+ for (let i = 7; i >= 0; --i) {
1672
+ buf[p + i] = dstOffset & 0xFF;
1673
+ dstOffset /= 256;
1674
+ }
1675
+
1676
+ this._requests[reqid] = { cb };
1677
+
1678
+ const isBuffered = sendOrBuffer(this, buf);
1679
+ if (this._debug) {
1680
+ const status = (isBuffered ? 'Buffered' : 'Sending');
1681
+ this._debug(`SFTP: Outbound: ${status} copy-data`);
1682
+ }
1683
+ }
1599
1684
  // ===========================================================================
1600
1685
  // Server-specific ===========================================================
1601
1686
  // ===========================================================================
@@ -1922,11 +2007,12 @@ function read_(self, handle, buf, off, len, position, cb, req_) {
1922
2007
  return;
1923
2008
  }
1924
2009
 
2010
+ nb = (nb || 0);
1925
2011
  if (req.origOff === 0 && buf.length === req.nb)
1926
2012
  data = buf;
1927
2013
  else
1928
- data = bufferSlice(buf, req.origOff, req.origOff + req.nb);
1929
- cb(undefined, req.nb + (nb || 0), data, req.position);
2014
+ data = bufferSlice(buf, req.origOff, req.origOff + req.nb + nb);
2015
+ cb(undefined, req.nb + nb, data, req.position);
1930
2016
  },
1931
2017
  buffer: undefined,
1932
2018
  });
@@ -2416,7 +2502,8 @@ function tryWritePayload(sftp, payload) {
2416
2502
  return;
2417
2503
 
2418
2504
  if (outgoing.window === 0) {
2419
- sftp._waitWindow = true; // XXX: Unnecessary?
2505
+ sftp._waitWindow = true;
2506
+ sftp._chunkcb = drainBuffer;
2420
2507
  return payload;
2421
2508
  }
2422
2509
 
@@ -2593,14 +2680,13 @@ const CLIENT_HANDLERS = {
2593
2680
  */
2594
2681
  const errorCode = bufferParser.readUInt32BE();
2595
2682
  const errorMsg = bufferParser.readString(true);
2596
- const lang = bufferParser.skipString();
2597
2683
  bufferParser.clear();
2598
2684
 
2599
- if (lang === undefined) {
2600
- if (reqID !== undefined)
2601
- delete sftp._requests[reqID];
2602
- return doFatalSFTPError(sftp, 'Malformed STATUS packet');
2603
- }
2685
+ // Note: we avoid checking that the error message and language tag are in
2686
+ // the packet because there are some broken implementations that incorrectly
2687
+ // omit them. The language tag in general was never really used amongst ssh
2688
+ // implementations, so in the case of a missing error message we just
2689
+ // default to something sensible.
2604
2690
 
2605
2691
  if (sftp._debug) {
2606
2692
  const jsonMsg = JSON.stringify(errorMsg);
@@ -3387,7 +3473,7 @@ function ReadStream(sftp, path, options) {
3387
3473
  this.autoClose = options.autoClose === undefined ? true : options.autoClose;
3388
3474
  this.pos = 0;
3389
3475
  this.bytesRead = 0;
3390
- this.closed = false;
3476
+ this.isClosed = false;
3391
3477
 
3392
3478
  this.handle = options.handle === undefined ? null : options.handle;
3393
3479
  this.sftp = sftp;
@@ -3539,7 +3625,7 @@ function closeStream(stream, cb, err) {
3539
3625
  function onclose(er) {
3540
3626
  er = er || err;
3541
3627
  cb(er);
3542
- stream.closed = true;
3628
+ stream.isClosed = true;
3543
3629
  if (!er)
3544
3630
  stream.emit('close');
3545
3631
  }
@@ -3582,7 +3668,7 @@ function WriteStream(sftp, path, options) {
3582
3668
  this.autoClose = options.autoClose === undefined ? true : options.autoClose;
3583
3669
  this.pos = 0;
3584
3670
  this.bytesWritten = 0;
3585
- this.closed = false;
3671
+ this.isClosed = false;
3586
3672
 
3587
3673
  this.handle = options.handle === undefined ? null : options.handle;
3588
3674
  this.sftp = sftp;
@@ -3742,7 +3828,7 @@ if (typeof WritableStream.prototype.destroy !== 'function')
3742
3828
  WriteStream.prototype._destroy = ReadStream.prototype._destroy;
3743
3829
  WriteStream.prototype.close = function(cb) {
3744
3830
  if (cb) {
3745
- if (this.closed) {
3831
+ if (this.isClosed) {
3746
3832
  process.nextTick(cb);
3747
3833
  return;
3748
3834
  }
@@ -7,7 +7,7 @@ try {
7
7
  cpuInfo = require('cpu-features')();
8
8
  } catch {}
9
9
 
10
- const { bindingAvailable } = require('./crypto.js');
10
+ const { bindingAvailable, CIPHER_INFO, MAC_INFO } = require('./crypto.js');
11
11
 
12
12
  const eddsaSupported = (() => {
13
13
  if (typeof crypto.sign === 'function'
@@ -76,7 +76,11 @@ const SUPPORTED_SERVER_HOST_KEY = DEFAULT_SERVER_HOST_KEY.concat([
76
76
  ]);
77
77
 
78
78
 
79
- const DEFAULT_CIPHER = [
79
+ const canUseCipher = (() => {
80
+ const ciphers = crypto.getCiphers();
81
+ return (name) => ciphers.includes(CIPHER_INFO[name].sslName);
82
+ })();
83
+ let DEFAULT_CIPHER = [
80
84
  // http://tools.ietf.org/html/rfc5647
81
85
  'aes128-gcm@openssh.com',
82
86
  'aes256-gcm@openssh.com',
@@ -99,12 +103,15 @@ if (cpuInfo && cpuInfo.flags && !cpuInfo.flags.aes) {
99
103
  } else {
100
104
  DEFAULT_CIPHER.push('chacha20-poly1305@openssh.com');
101
105
  }
106
+ DEFAULT_CIPHER = DEFAULT_CIPHER.filter(canUseCipher);
102
107
  const SUPPORTED_CIPHER = DEFAULT_CIPHER.concat([
103
108
  'aes256-cbc',
104
109
  'aes192-cbc',
105
110
  'aes128-cbc',
106
111
  'blowfish-cbc',
107
112
  '3des-cbc',
113
+ 'aes128-gcm',
114
+ 'aes256-gcm',
108
115
 
109
116
  // http://tools.ietf.org/html/rfc4345#section-4:
110
117
  'arcfour256',
@@ -112,9 +119,13 @@ const SUPPORTED_CIPHER = DEFAULT_CIPHER.concat([
112
119
 
113
120
  'cast128-cbc',
114
121
  'arcfour',
115
- ]);
122
+ ].filter(canUseCipher));
116
123
 
117
124
 
125
+ const canUseMAC = (() => {
126
+ const hashes = crypto.getHashes();
127
+ return (name) => hashes.includes(MAC_INFO[name].sslName);
128
+ })();
118
129
  const DEFAULT_MAC = [
119
130
  'hmac-sha2-256-etm@openssh.com',
120
131
  'hmac-sha2-512-etm@openssh.com',
@@ -122,7 +133,7 @@ const DEFAULT_MAC = [
122
133
  'hmac-sha2-256',
123
134
  'hmac-sha2-512',
124
135
  'hmac-sha1',
125
- ];
136
+ ].filter(canUseMAC);
126
137
  const SUPPORTED_MAC = DEFAULT_MAC.concat([
127
138
  'hmac-md5',
128
139
  'hmac-sha2-256-96', // first 96 bits of HMAC-SHA256
@@ -130,7 +141,7 @@ const SUPPORTED_MAC = DEFAULT_MAC.concat([
130
141
  'hmac-ripemd160',
131
142
  'hmac-sha1-96', // first 96 bits of HMAC-SHA1
132
143
  'hmac-md5-96', // first 96 bits of HMAC-MD5
133
- ]);
144
+ ].filter(canUseMAC));
134
145
 
135
146
  const DEFAULT_COMPRESSION = [
136
147
  'none',
@@ -1,4 +1,7 @@
1
1
  {
2
+ 'variables': {
3
+ 'real_openssl_major%': '0',
4
+ },
2
5
  'targets': [
3
6
  {
4
7
  'target_name': 'sshcrypto',
@@ -9,6 +12,12 @@
9
12
  'src/binding.cc'
10
13
  ],
11
14
  'cflags': [ '-O3' ],
15
+
16
+ # Needed for OpenSSL 3.x/node.js v17.x+
17
+ 'defines': [
18
+ 'OPENSSL_API_COMPAT=0x10100000L',
19
+ 'REAL_OPENSSL_MAJOR=<(real_openssl_major)',
20
+ ],
12
21
  },
13
22
  ],
14
23
  }
@@ -1,16 +1,49 @@
1
- // TODO: switch from obsolete EVP_* APIs in CCP
1
+ #if defined(__GNUC__) && __GNUC__ >= 8
2
+ #define DISABLE_WCAST_FUNCTION_TYPE _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wcast-function-type\"")
3
+ #define DISABLE_WCAST_FUNCTION_TYPE_END _Pragma("GCC diagnostic pop")
4
+ #else
5
+ #define DISABLE_WCAST_FUNCTION_TYPE
6
+ #define DISABLE_WCAST_FUNCTION_TYPE_END
7
+ #endif
8
+
2
9
  #include <stdio.h>
3
10
  #include <string.h>
4
11
  #include <assert.h>
5
12
 
13
+ DISABLE_WCAST_FUNCTION_TYPE
6
14
  #include <node.h>
7
15
  #include <node_buffer.h>
8
16
  #include <nan.h>
17
+ DISABLE_WCAST_FUNCTION_TYPE_END
18
+
19
+ #if NODE_MAJOR_VERSION >= 17
20
+ # include <openssl/configuration.h>
21
+ #endif
9
22
 
10
23
  #include <openssl/err.h>
11
24
  #include <openssl/evp.h>
12
25
  #include <openssl/hmac.h>
13
26
 
27
+ #ifndef _WIN32
28
+ # include <dlfcn.h>
29
+ #endif
30
+
31
+ typedef int (*ctx_iv_len_func)(const EVP_CIPHER_CTX*);
32
+ typedef int (*ctx_key_len_func)(const EVP_CIPHER_CTX*);
33
+ typedef int (*ctx_get_block_size_func)(const EVP_CIPHER_CTX*);
34
+ typedef int (*cipher_flags_func)(const EVP_CIPHER*);
35
+ ctx_iv_len_func ctx_iv_len = nullptr;
36
+ ctx_key_len_func ctx_key_len = nullptr;
37
+ ctx_get_block_size_func ctx_get_block_size = nullptr;
38
+ cipher_flags_func cipher_flags = nullptr;
39
+
40
+ #if REAL_OPENSSL_MAJOR < 3
41
+ # undef EVP_DigestSignUpdate
42
+ # define EVP_DigestSignUpdate EVP_DigestUpdate
43
+ # undef EVP_PKEY_OP_SIGNCTX
44
+ # define EVP_PKEY_OP_SIGNCTX (1 << 6)
45
+ #endif
46
+
14
47
  using namespace node;
15
48
  using namespace v8;
16
49
  using namespace std;
@@ -62,8 +95,14 @@ class ChaChaPolyCipher : public ObjectWrap {
62
95
  explicit ChaChaPolyCipher()
63
96
  : ctx_main_(nullptr),
64
97
  ctx_pktlen_(nullptr),
98
+ #if REAL_OPENSSL_MAJOR >= 3
99
+ mac_(nullptr),
100
+ mac_ctx_(nullptr) {}
101
+ #else
65
102
  md_ctx_(nullptr),
66
- polykey_(nullptr) {}
103
+ polykey_(nullptr),
104
+ polykey_ctx_(nullptr) {}
105
+ #endif
67
106
 
68
107
  ~ChaChaPolyCipher() {
69
108
  clear();
@@ -71,15 +110,23 @@ class ChaChaPolyCipher : public ObjectWrap {
71
110
 
72
111
  void clear() {
73
112
  if (ctx_pktlen_) {
74
- EVP_CIPHER_CTX_cleanup(ctx_pktlen_);
75
113
  EVP_CIPHER_CTX_free(ctx_pktlen_);
76
114
  ctx_pktlen_ = nullptr;
77
115
  }
78
116
  if (ctx_main_) {
79
- EVP_CIPHER_CTX_cleanup(ctx_main_);
80
117
  EVP_CIPHER_CTX_free(ctx_main_);
81
118
  ctx_main_ = nullptr;
82
119
  }
120
+ #if REAL_OPENSSL_MAJOR >= 3
121
+ if (mac_ctx_) {
122
+ EVP_MAC_CTX_free(mac_ctx_);
123
+ mac_ctx_ = nullptr;
124
+ }
125
+ if (mac_) {
126
+ EVP_MAC_free(mac_);
127
+ mac_ = nullptr;
128
+ }
129
+ #else
83
130
  if (polykey_) {
84
131
  EVP_PKEY_free(polykey_);
85
132
  polykey_ = nullptr;
@@ -90,6 +137,7 @@ class ChaChaPolyCipher : public ObjectWrap {
90
137
  }
91
138
  // `polykey_ctx_` is not explicitly freed as it is freed implicitly when
92
139
  // `md_ctx_` is freed
140
+ #endif
93
141
  }
94
142
 
95
143
  ErrorType init(unsigned char* keys, size_t keys_len) {
@@ -108,7 +156,14 @@ class ChaChaPolyCipher : public ObjectWrap {
108
156
 
109
157
  if ((ctx_pktlen_ = EVP_CIPHER_CTX_new()) == nullptr
110
158
  || (ctx_main_ = EVP_CIPHER_CTX_new()) == nullptr
159
+ #if REAL_OPENSSL_MAJOR >= 3
160
+ || (mac_ = EVP_MAC_fetch(nullptr,
161
+ "POLY1305",
162
+ "provider=default")) == nullptr
163
+ || (mac_ctx_ = EVP_MAC_CTX_new(mac_)) == nullptr
164
+ #else
111
165
  || (md_ctx_ = EVP_MD_CTX_new()) == nullptr
166
+ #endif
112
167
  || EVP_EncryptInit_ex(ctx_pktlen_,
113
168
  cipher,
114
169
  nullptr,
@@ -122,7 +177,7 @@ class ChaChaPolyCipher : public ObjectWrap {
122
177
  r = kErrOpenSSL;
123
178
  goto out;
124
179
  }
125
- if (EVP_CIPHER_CTX_iv_length(ctx_pktlen_) != 16) {
180
+ if (ctx_iv_len(ctx_pktlen_) != 16) {
126
181
  r = kErrBadIVLen;
127
182
  goto out;
128
183
  }
@@ -206,6 +261,16 @@ out:
206
261
  }
207
262
 
208
263
  // Poly1305 over ciphertext
264
+ #if REAL_OPENSSL_MAJOR >= 3
265
+ // TODO: check if dup()'ing a "base" context instead of calling init() with
266
+ // the key each time is faster
267
+ if (EVP_MAC_init(mac_ctx_, polykey, sizeof(polykey), nullptr) != 1
268
+ || EVP_MAC_update(mac_ctx_, packet, data_len) != 1
269
+ || EVP_MAC_final(mac_ctx_, packet + data_len, &sig_len, sig_len) != 1) {
270
+ r = kErrOpenSSL;
271
+ goto out;
272
+ }
273
+ #else
209
274
  if (polykey_) {
210
275
  if (EVP_PKEY_CTX_ctrl(polykey_ctx_,
211
276
  -1,
@@ -245,9 +310,10 @@ out:
245
310
  r = kErrOpenSSL;
246
311
  goto out;
247
312
  }
313
+ #endif
248
314
 
249
- out:
250
- return r;
315
+ out:
316
+ return r;
251
317
  }
252
318
 
253
319
  static NAN_METHOD(New) {
@@ -328,9 +394,14 @@ out:
328
394
 
329
395
  EVP_CIPHER_CTX* ctx_main_;
330
396
  EVP_CIPHER_CTX* ctx_pktlen_;
397
+ #if REAL_OPENSSL_MAJOR >= 3
398
+ EVP_MAC* mac_;
399
+ EVP_MAC_CTX* mac_ctx_;
400
+ #else
331
401
  EVP_MD_CTX* md_ctx_;
332
402
  EVP_PKEY* polykey_;
333
403
  EVP_PKEY_CTX* polykey_ctx_;
404
+ #endif
334
405
  };
335
406
 
336
407
  class AESGCMCipher : public ObjectWrap {
@@ -359,7 +430,6 @@ class AESGCMCipher : public ObjectWrap {
359
430
 
360
431
  void clear() {
361
432
  if (ctx_) {
362
- EVP_CIPHER_CTX_cleanup(ctx_);
363
433
  EVP_CIPHER_CTX_free(ctx_);
364
434
  ctx_ = nullptr;
365
435
  }
@@ -394,12 +464,7 @@ class AESGCMCipher : public ObjectWrap {
394
464
  goto out;
395
465
  }
396
466
 
397
- //~ if (iv_len != static_cast<size_t>(EVP_CIPHER_CTX_iv_length(ctx_))) {
398
- //~ r = kErrBadIVLen;
399
- //~ goto out;
400
- //~ }
401
-
402
- if (key_len != static_cast<size_t>(EVP_CIPHER_CTX_key_length(ctx_))) {
467
+ if (key_len != static_cast<size_t>(ctx_key_len(ctx_))) {
403
468
  if (!EVP_CIPHER_CTX_set_key_length(ctx_, key_len)) {
404
469
  r = kErrBadKeyLen;
405
470
  goto out;
@@ -596,7 +661,12 @@ class GenericCipher : public ObjectWrap {
596
661
  private:
597
662
  explicit GenericCipher()
598
663
  : ctx_(nullptr),
664
+ #if REAL_OPENSSL_MAJOR >= 3
665
+ mac_(nullptr),
666
+ mac_ctx_base_(nullptr),
667
+ #else
599
668
  ctx_hmac_(nullptr),
669
+ #endif
600
670
  hmac_len_(0),
601
671
  is_etm_(0) {}
602
672
 
@@ -606,14 +676,24 @@ class GenericCipher : public ObjectWrap {
606
676
 
607
677
  void clear() {
608
678
  if (ctx_) {
609
- EVP_CIPHER_CTX_cleanup(ctx_);
610
679
  EVP_CIPHER_CTX_free(ctx_);
611
680
  ctx_ = nullptr;
612
681
  }
682
+ #if REAL_OPENSSL_MAJOR >= 3
683
+ if (mac_ctx_base_) {
684
+ EVP_MAC_CTX_free(mac_ctx_base_);
685
+ mac_ctx_base_ = nullptr;
686
+ }
687
+ if (mac_) {
688
+ EVP_MAC_free(mac_);
689
+ mac_ = nullptr;
690
+ }
691
+ #else
613
692
  if (ctx_hmac_) {
614
693
  HMAC_CTX_free(ctx_hmac_);
615
694
  ctx_hmac_ = nullptr;
616
695
  }
696
+ #endif
617
697
  }
618
698
 
619
699
  ErrorType init(const char* name,
@@ -627,7 +707,11 @@ class GenericCipher : public ObjectWrap {
627
707
  int is_etm) {
628
708
  ErrorType r = kErrNone;
629
709
 
710
+ #if REAL_OPENSSL_MAJOR >= 3
711
+ OSSL_PARAM params[2];
712
+ #else
630
713
  const EVP_MD* md;
714
+ #endif
631
715
  const EVP_CIPHER* const cipher = EVP_get_cipherbyname(name);
632
716
  if (cipher == nullptr) {
633
717
  r = kErrOpenSSL;
@@ -640,12 +724,12 @@ class GenericCipher : public ObjectWrap {
640
724
  goto out;
641
725
  }
642
726
 
643
- if (iv_len != static_cast<size_t>(EVP_CIPHER_CTX_iv_length(ctx_))) {
727
+ if (iv_len != static_cast<size_t>(ctx_iv_len(ctx_))) {
644
728
  r = kErrBadIVLen;
645
729
  goto out;
646
730
  }
647
731
 
648
- if (key_len != static_cast<size_t>(EVP_CIPHER_CTX_key_length(ctx_))) {
732
+ if (key_len != static_cast<size_t>(ctx_key_len(ctx_))) {
649
733
  if (!EVP_CIPHER_CTX_set_key_length(ctx_, key_len)) {
650
734
  r = kErrBadKeyLen;
651
735
  goto out;
@@ -685,6 +769,28 @@ class GenericCipher : public ObjectWrap {
685
769
  }
686
770
  }
687
771
 
772
+ #if REAL_OPENSSL_MAJOR >= 3
773
+ if ((mac_ = EVP_MAC_fetch(nullptr,
774
+ "HMAC",
775
+ "provider=default")) == nullptr) {
776
+ r = kErrOpenSSL;
777
+ goto out;
778
+ }
779
+ if ((mac_ctx_base_ = EVP_MAC_CTX_new(mac_)) == nullptr) {
780
+ r = kErrOpenSSL;
781
+ goto out;
782
+ }
783
+ params[0] = OSSL_PARAM_construct_utf8_string("digest",
784
+ const_cast<char*>(hmac_name),
785
+ 0);
786
+ params[1] = OSSL_PARAM_END;
787
+ if (EVP_MAC_init(mac_ctx_base_, hmac_key, hmac_key_len, params) != 1) {
788
+ EVP_MAC_CTX_free(mac_ctx_base_);
789
+ r = kErrOpenSSL;
790
+ goto out;
791
+ }
792
+ hmac_len_ = EVP_MAC_CTX_get_mac_size(mac_ctx_base_);
793
+ #else
688
794
  md = EVP_get_digestbyname(hmac_name);
689
795
  if (md == nullptr) {
690
796
  r = kErrBadHMACName;
@@ -698,6 +804,7 @@ class GenericCipher : public ObjectWrap {
698
804
  }
699
805
 
700
806
  hmac_len_ = HMAC_size(ctx_hmac_);
807
+ #endif
701
808
  is_etm_ = is_etm;
702
809
 
703
810
  out:
@@ -735,39 +842,51 @@ out:
735
842
  r = kErrPartialEncrypt;
736
843
  goto out;
737
844
  }
845
+ }
846
+
847
+ // Calculate HMAC
848
+ {
849
+ #if REAL_OPENSSL_MAJOR >= 3
850
+ size_t outlen = hmac_len_;
738
851
 
739
- // HMAC over unencrypted packet length and ciphertext
740
- {
741
- unsigned int outlen = hmac_len_;
742
- if (HMAC_Init_ex(ctx_hmac_, nullptr, 0, nullptr, nullptr) != 1
743
- || HMAC_Update(ctx_hmac_, seqbuf, sizeof(seqbuf)) != 1
744
- || HMAC_Update(ctx_hmac_, packet, data_len) != 1
745
- || HMAC_Final(ctx_hmac_, packet + data_len, &outlen) != 1) {
746
- r = kErrOpenSSL;
747
- goto out;
748
- }
749
- if (outlen != hmac_len_) {
750
- r = kErrBadHMACLen;
751
- goto out;
752
- }
852
+ EVP_MAC_CTX* mac_ctx = EVP_MAC_CTX_dup(mac_ctx_base_);
853
+ if (mac_ctx == nullptr) {
854
+ r = kErrOpenSSL;
855
+ goto out;
753
856
  }
754
- } else {
755
- // HMAC over plaintext
756
- {
757
- unsigned int outlen = hmac_len_;
758
- if (HMAC_Init_ex(ctx_hmac_, nullptr, 0, nullptr, nullptr) != 1
759
- || HMAC_Update(ctx_hmac_, seqbuf, sizeof(seqbuf)) != 1
760
- || HMAC_Update(ctx_hmac_, packet, data_len) != 1
761
- || HMAC_Final(ctx_hmac_, packet + data_len, &outlen) != 1) {
762
- r = kErrOpenSSL;
763
- goto out;
764
- }
765
- if (outlen != hmac_len_) {
766
- r = kErrBadHMACLen;
767
- goto out;
768
- }
857
+ if (EVP_MAC_update(mac_ctx, seqbuf, sizeof(seqbuf)) != 1
858
+ || EVP_MAC_update(mac_ctx, packet, data_len) != 1
859
+ || EVP_MAC_final(mac_ctx,
860
+ packet + data_len,
861
+ reinterpret_cast<size_t*>(&outlen),
862
+ outlen) != 1) {
863
+ EVP_MAC_CTX_free(mac_ctx);
864
+ r = kErrOpenSSL;
865
+ goto out;
866
+ }
867
+ if (outlen != hmac_len_) {
868
+ EVP_MAC_CTX_free(mac_ctx);
869
+ r = kErrBadHMACLen;
870
+ goto out;
769
871
  }
872
+ EVP_MAC_CTX_free(mac_ctx);
873
+ #else
874
+ unsigned int outlen = hmac_len_;
875
+ if (HMAC_Init_ex(ctx_hmac_, nullptr, 0, nullptr, nullptr) != 1
876
+ || HMAC_Update(ctx_hmac_, seqbuf, sizeof(seqbuf)) != 1
877
+ || HMAC_Update(ctx_hmac_, packet, data_len) != 1
878
+ || HMAC_Final(ctx_hmac_, packet + data_len, &outlen) != 1) {
879
+ r = kErrOpenSSL;
880
+ goto out;
881
+ }
882
+ if (outlen != hmac_len_) {
883
+ r = kErrBadHMACLen;
884
+ goto out;
885
+ }
886
+ #endif
887
+ }
770
888
 
889
+ if (!is_etm_) {
771
890
  // Encrypt packet
772
891
  if (EVP_EncryptUpdate(ctx_,
773
892
  packet,
@@ -901,8 +1020,14 @@ out:
901
1020
  }
902
1021
 
903
1022
  EVP_CIPHER_CTX* ctx_;
1023
+ #if REAL_OPENSSL_MAJOR >= 3
1024
+ EVP_MAC* mac_;
1025
+ EVP_MAC_CTX* mac_ctx_base_;
1026
+ size_t hmac_len_;
1027
+ #else
904
1028
  HMAC_CTX* ctx_hmac_;
905
1029
  unsigned int hmac_len_;
1030
+ #endif
906
1031
  int is_etm_;
907
1032
  };
908
1033
 
@@ -930,8 +1055,14 @@ class ChaChaPolyDecipher : public ObjectWrap {
930
1055
  explicit ChaChaPolyDecipher()
931
1056
  : ctx_main_(nullptr),
932
1057
  ctx_pktlen_(nullptr),
1058
+ #if REAL_OPENSSL_MAJOR >= 3
1059
+ mac_(nullptr),
1060
+ mac_ctx_(nullptr) {}
1061
+ #else
933
1062
  md_ctx_(nullptr),
934
- polykey_(nullptr) {}
1063
+ polykey_(nullptr),
1064
+ polykey_ctx_(nullptr) {}
1065
+ #endif
935
1066
 
936
1067
  ~ChaChaPolyDecipher() {
937
1068
  clear();
@@ -939,15 +1070,23 @@ class ChaChaPolyDecipher : public ObjectWrap {
939
1070
 
940
1071
  void clear() {
941
1072
  if (ctx_pktlen_) {
942
- EVP_CIPHER_CTX_cleanup(ctx_pktlen_);
943
1073
  EVP_CIPHER_CTX_free(ctx_pktlen_);
944
1074
  ctx_pktlen_ = nullptr;
945
1075
  }
946
1076
  if (ctx_main_) {
947
- EVP_CIPHER_CTX_cleanup(ctx_main_);
948
1077
  EVP_CIPHER_CTX_free(ctx_main_);
949
1078
  ctx_main_ = nullptr;
950
1079
  }
1080
+ #if REAL_OPENSSL_MAJOR >= 3
1081
+ if (mac_ctx_) {
1082
+ EVP_MAC_CTX_free(mac_ctx_);
1083
+ mac_ctx_ = nullptr;
1084
+ }
1085
+ if (mac_) {
1086
+ EVP_MAC_free(mac_);
1087
+ mac_ = nullptr;
1088
+ }
1089
+ #else
951
1090
  if (polykey_) {
952
1091
  EVP_PKEY_free(polykey_);
953
1092
  polykey_ = nullptr;
@@ -958,6 +1097,7 @@ class ChaChaPolyDecipher : public ObjectWrap {
958
1097
  }
959
1098
  // `polykey_ctx_` is not explicitly freed as it is freed implicitly when
960
1099
  // `md_ctx_` is freed
1100
+ #endif
961
1101
  }
962
1102
 
963
1103
  ErrorType init(unsigned char* keys, size_t keys_len) {
@@ -976,7 +1116,14 @@ class ChaChaPolyDecipher : public ObjectWrap {
976
1116
 
977
1117
  if ((ctx_pktlen_ = EVP_CIPHER_CTX_new()) == nullptr
978
1118
  || (ctx_main_ = EVP_CIPHER_CTX_new()) == nullptr
1119
+ #if REAL_OPENSSL_MAJOR >= 3
1120
+ || (mac_ = EVP_MAC_fetch(nullptr,
1121
+ "POLY1305",
1122
+ "provider=default")) == nullptr
1123
+ || (mac_ctx_ = EVP_MAC_CTX_new(mac_)) == nullptr
1124
+ #else
979
1125
  || (md_ctx_ = EVP_MD_CTX_new()) == nullptr
1126
+ #endif
980
1127
  || EVP_DecryptInit_ex(ctx_pktlen_,
981
1128
  cipher,
982
1129
  nullptr,
@@ -990,7 +1137,7 @@ class ChaChaPolyDecipher : public ObjectWrap {
990
1137
  r = kErrOpenSSL;
991
1138
  goto out;
992
1139
  }
993
- if (EVP_CIPHER_CTX_iv_length(ctx_pktlen_) != 16) {
1140
+ if (ctx_iv_len(ctx_pktlen_) != 16) {
994
1141
  r = kErrBadIVLen;
995
1142
  goto out;
996
1143
  }
@@ -1083,6 +1230,17 @@ out:
1083
1230
  }
1084
1231
 
1085
1232
  // Poly1305 over ciphertext
1233
+ #if REAL_OPENSSL_MAJOR >= 3
1234
+ // TODO: check if dup()'ing a "base" context instead of calling init() with
1235
+ // the key each time is faster
1236
+ if (EVP_MAC_init(mac_ctx_, polykey, sizeof(polykey), nullptr) != 1
1237
+ || EVP_MAC_update(mac_ctx_, length_bytes, sizeof(length_bytes)) != 1
1238
+ || EVP_MAC_update(mac_ctx_, packet, packet_len) != 1
1239
+ || EVP_MAC_final(mac_ctx_, calc_mac, &sig_len, sig_len) != 1) {
1240
+ r = kErrOpenSSL;
1241
+ goto out;
1242
+ }
1243
+ #else
1086
1244
  if (polykey_) {
1087
1245
  if (EVP_PKEY_CTX_ctrl(polykey_ctx_,
1088
1246
  -1,
@@ -1128,6 +1286,7 @@ out:
1128
1286
  r = kErrOpenSSL;
1129
1287
  goto out;
1130
1288
  }
1289
+ #endif
1131
1290
 
1132
1291
  // Compare MACs
1133
1292
  if (CRYPTO_memcmp(mac, calc_mac, sizeof(calc_mac))) {
@@ -1289,9 +1448,14 @@ out:
1289
1448
  unsigned char length_bytes[4];
1290
1449
  EVP_CIPHER_CTX* ctx_main_;
1291
1450
  EVP_CIPHER_CTX* ctx_pktlen_;
1451
+ #if REAL_OPENSSL_MAJOR >= 3
1452
+ EVP_MAC* mac_;
1453
+ EVP_MAC_CTX* mac_ctx_;
1454
+ #else
1292
1455
  EVP_MD_CTX* md_ctx_;
1293
1456
  EVP_PKEY* polykey_;
1294
1457
  EVP_PKEY_CTX* polykey_ctx_;
1458
+ #endif
1295
1459
  };
1296
1460
 
1297
1461
  class AESGCMDecipher : public ObjectWrap {
@@ -1320,7 +1484,6 @@ class AESGCMDecipher : public ObjectWrap {
1320
1484
 
1321
1485
  void clear() {
1322
1486
  if (ctx_) {
1323
- EVP_CIPHER_CTX_cleanup(ctx_);
1324
1487
  EVP_CIPHER_CTX_free(ctx_);
1325
1488
  ctx_ = nullptr;
1326
1489
  }
@@ -1355,12 +1518,7 @@ class AESGCMDecipher : public ObjectWrap {
1355
1518
  goto out;
1356
1519
  }
1357
1520
 
1358
- //~ if (iv_len != static_cast<size_t>(EVP_CIPHER_CTX_iv_length(ctx_))) {
1359
- //~ r = kErrBadIVLen;
1360
- //~ goto out;
1361
- //~ }
1362
-
1363
- if (key_len != static_cast<size_t>(EVP_CIPHER_CTX_key_length(ctx_))) {
1521
+ if (key_len != static_cast<size_t>(ctx_key_len(ctx_))) {
1364
1522
  if (!EVP_CIPHER_CTX_set_key_length(ctx_, key_len)) {
1365
1523
  r = kErrBadKeyLen;
1366
1524
  goto out;
@@ -1568,7 +1726,12 @@ class GenericDecipher : public ObjectWrap {
1568
1726
  private:
1569
1727
  explicit GenericDecipher()
1570
1728
  : ctx_(nullptr),
1729
+ #if REAL_OPENSSL_MAJOR >= 3
1730
+ mac_(nullptr),
1731
+ mac_ctx_base_(nullptr),
1732
+ #else
1571
1733
  ctx_hmac_(nullptr),
1734
+ #endif
1572
1735
  hmac_len_(0),
1573
1736
  is_etm_(0) {}
1574
1737
 
@@ -1578,14 +1741,24 @@ class GenericDecipher : public ObjectWrap {
1578
1741
 
1579
1742
  void clear() {
1580
1743
  if (ctx_) {
1581
- EVP_CIPHER_CTX_cleanup(ctx_);
1582
1744
  EVP_CIPHER_CTX_free(ctx_);
1583
1745
  ctx_ = nullptr;
1584
1746
  }
1747
+ #if REAL_OPENSSL_MAJOR >= 3
1748
+ if (mac_ctx_base_) {
1749
+ EVP_MAC_CTX_free(mac_ctx_base_);
1750
+ mac_ctx_base_ = nullptr;
1751
+ }
1752
+ if (mac_) {
1753
+ EVP_MAC_free(mac_);
1754
+ mac_ = nullptr;
1755
+ }
1756
+ #else
1585
1757
  if (ctx_hmac_) {
1586
1758
  HMAC_CTX_free(ctx_hmac_);
1587
1759
  ctx_hmac_ = nullptr;
1588
1760
  }
1761
+ #endif
1589
1762
  }
1590
1763
 
1591
1764
  ErrorType init(const char* name,
@@ -1600,7 +1773,11 @@ class GenericDecipher : public ObjectWrap {
1600
1773
  size_t hmac_actual_len) {
1601
1774
  ErrorType r = kErrNone;
1602
1775
 
1776
+ #if REAL_OPENSSL_MAJOR >= 3
1777
+ OSSL_PARAM params[2];
1778
+ #else
1603
1779
  const EVP_MD* md;
1780
+ #endif
1604
1781
  const EVP_CIPHER* const cipher = EVP_get_cipherbyname(name);
1605
1782
  if (cipher == nullptr) {
1606
1783
  r = kErrOpenSSL;
@@ -1613,12 +1790,12 @@ class GenericDecipher : public ObjectWrap {
1613
1790
  goto out;
1614
1791
  }
1615
1792
 
1616
- if (iv_len != static_cast<size_t>(EVP_CIPHER_CTX_iv_length(ctx_))) {
1793
+ if (iv_len != static_cast<size_t>(ctx_iv_len(ctx_))) {
1617
1794
  r = kErrBadIVLen;
1618
1795
  goto out;
1619
1796
  }
1620
1797
 
1621
- if (key_len != static_cast<size_t>(EVP_CIPHER_CTX_key_length(ctx_))) {
1798
+ if (key_len != static_cast<size_t>(ctx_key_len(ctx_))) {
1622
1799
  if (!EVP_CIPHER_CTX_set_key_length(ctx_, key_len)) {
1623
1800
  r = kErrBadKeyLen;
1624
1801
  goto out;
@@ -1658,6 +1835,28 @@ class GenericDecipher : public ObjectWrap {
1658
1835
  }
1659
1836
  }
1660
1837
 
1838
+ #if REAL_OPENSSL_MAJOR >= 3
1839
+ if ((mac_ = EVP_MAC_fetch(nullptr,
1840
+ "HMAC",
1841
+ "provider=default")) == nullptr) {
1842
+ r = kErrOpenSSL;
1843
+ goto out;
1844
+ }
1845
+ if ((mac_ctx_base_ = EVP_MAC_CTX_new(mac_)) == nullptr) {
1846
+ r = kErrOpenSSL;
1847
+ goto out;
1848
+ }
1849
+ params[0] = OSSL_PARAM_construct_utf8_string("digest",
1850
+ const_cast<char*>(hmac_name),
1851
+ 0);
1852
+ params[1] = OSSL_PARAM_END;
1853
+ if (EVP_MAC_init(mac_ctx_base_, hmac_key, hmac_key_len, params) != 1) {
1854
+ EVP_MAC_CTX_free(mac_ctx_base_);
1855
+ r = kErrOpenSSL;
1856
+ goto out;
1857
+ }
1858
+ hmac_len_ = EVP_MAC_CTX_get_mac_size(mac_ctx_base_);
1859
+ #else
1661
1860
  md = EVP_get_digestbyname(hmac_name);
1662
1861
  if (md == nullptr) {
1663
1862
  r = kErrBadHMACName;
@@ -1671,9 +1870,14 @@ class GenericDecipher : public ObjectWrap {
1671
1870
  }
1672
1871
 
1673
1872
  hmac_len_ = HMAC_size(ctx_hmac_);
1873
+ #endif
1674
1874
  hmac_actual_len_ = hmac_actual_len;
1675
1875
  is_etm_ = is_etm;
1876
+ #if REAL_OPENSSL_MAJOR >= 3
1676
1877
  switch (EVP_CIPHER_CTX_mode(ctx_)) {
1878
+ #else
1879
+ switch (cipher_flags(EVP_CIPHER_CTX_cipher(ctx_)) & EVP_CIPH_MODE) {
1880
+ #endif
1677
1881
  case EVP_CIPH_STREAM_CIPHER:
1678
1882
  case EVP_CIPH_CTR_MODE:
1679
1883
  is_stream_ = 1;
@@ -1681,7 +1885,7 @@ class GenericDecipher : public ObjectWrap {
1681
1885
  default:
1682
1886
  is_stream_ = 0;
1683
1887
  }
1684
- block_size_ = EVP_CIPHER_CTX_block_size(ctx_);
1888
+ block_size_ = ctx_get_block_size(ctx_);
1685
1889
 
1686
1890
  out:
1687
1891
  return r;
@@ -1729,47 +1933,7 @@ out:
1729
1933
  ((uint8_t*)(seqbuf))[2] = (seqno >> 8) & 0xff;
1730
1934
  ((uint8_t*)(seqbuf))[3] = seqno & 0xff;
1731
1935
 
1732
- if (is_etm_) {
1733
- // `first_block` for ETM should just be the unencrypted packet length
1734
- if (first_block_len != 4) {
1735
- r = kErrBadBlockLen;
1736
- goto out;
1737
- }
1738
-
1739
- // HMAC over unencrypted packet length and ciphertext
1740
- {
1741
- unsigned int outlen = hmac_len_;
1742
- if (HMAC_Init_ex(ctx_hmac_, nullptr, 0, nullptr, nullptr) != 1
1743
- || HMAC_Update(ctx_hmac_, seqbuf, sizeof(seqbuf)) != 1
1744
- || HMAC_Update(ctx_hmac_, first_block, 4) != 1
1745
- || HMAC_Update(ctx_hmac_, packet, packet_len) != 1
1746
- || HMAC_Final(ctx_hmac_, calc_mac, &outlen) != 1) {
1747
- r = kErrOpenSSL;
1748
- goto out;
1749
- }
1750
-
1751
- if (outlen != hmac_len_ || mac_len != hmac_len_) {
1752
- r = kErrBadHMACLen;
1753
- goto out;
1754
- }
1755
-
1756
- // Compare MACs
1757
- if (CRYPTO_memcmp(mac, calc_mac, hmac_len_)) {
1758
- r = kErrInvalidMAC;
1759
- goto out;
1760
- }
1761
- }
1762
-
1763
- // Decrypt packet
1764
- if (EVP_DecryptUpdate(ctx_, packet, &outlen, packet, packet_len) != 1) {
1765
- r = kErrOpenSSL;
1766
- goto out;
1767
- }
1768
- if (static_cast<size_t>(outlen) != packet_len) {
1769
- r = kErrPartialDecrypt;
1770
- goto out;
1771
- }
1772
- } else {
1936
+ if (!is_etm_) {
1773
1937
  // `first_block` for non-ETM should be a completely decrypted first block
1774
1938
  if (!is_stream_ && first_block_len != block_size_) {
1775
1939
  r = kErrBadBlockLen;
@@ -1790,29 +1954,73 @@ out:
1790
1954
  r = kErrPartialDecrypt;
1791
1955
  goto out;
1792
1956
  }
1957
+ }
1958
+
1959
+ // Calculate and compare HMAC
1960
+ {
1961
+ #if REAL_OPENSSL_MAJOR >= 3
1962
+ size_t outlen = hmac_len_;
1963
+
1964
+ EVP_MAC_CTX* mac_ctx = EVP_MAC_CTX_dup(mac_ctx_base_);
1965
+ if (mac_ctx == nullptr) {
1966
+ r = kErrOpenSSL;
1967
+ goto out;
1968
+ }
1969
+ if (EVP_MAC_update(mac_ctx, seqbuf, sizeof(seqbuf)) != 1
1970
+ || EVP_MAC_update(mac_ctx, first_block, 4) != 1
1971
+ || EVP_MAC_update(mac_ctx, packet, packet_len) != 1
1972
+ || EVP_MAC_final(mac_ctx,
1973
+ calc_mac,
1974
+ &outlen,
1975
+ outlen) != 1) {
1976
+ EVP_MAC_CTX_free(mac_ctx);
1977
+ r = kErrOpenSSL;
1978
+ goto out;
1979
+ }
1980
+ if (outlen != hmac_len_ || mac_len != hmac_actual_len_) {
1981
+ EVP_MAC_CTX_free(mac_ctx);
1982
+ r = kErrBadHMACLen;
1983
+ goto out;
1984
+ }
1985
+ EVP_MAC_CTX_free(mac_ctx);
1986
+ #else
1987
+ unsigned int outlen = hmac_len_;
1988
+ if (HMAC_Init_ex(ctx_hmac_, nullptr, 0, nullptr, nullptr) != 1
1989
+ || HMAC_Update(ctx_hmac_, seqbuf, sizeof(seqbuf)) != 1
1990
+ || HMAC_Update(ctx_hmac_, first_block, 4) != 1
1991
+ || HMAC_Update(ctx_hmac_, packet, packet_len) != 1
1992
+ || HMAC_Final(ctx_hmac_, calc_mac, &outlen) != 1) {
1993
+ r = kErrOpenSSL;
1994
+ goto out;
1995
+ }
1996
+ if (outlen != hmac_len_ || mac_len != hmac_actual_len_) {
1997
+ r = kErrBadHMACLen;
1998
+ goto out;
1999
+ }
2000
+ #endif
2001
+
2002
+ // Compare MACs
2003
+ if (CRYPTO_memcmp(mac, calc_mac, hmac_actual_len_)) {
2004
+ r = kErrInvalidMAC;
2005
+ goto out;
2006
+ }
2007
+ }
1793
2008
 
1794
- // HMAC over plaintext
1795
- {
1796
- unsigned int outlen = hmac_len_;
1797
- if (HMAC_Init_ex(ctx_hmac_, nullptr, 0, nullptr, nullptr) != 1
1798
- || HMAC_Update(ctx_hmac_, seqbuf, sizeof(seqbuf)) != 1
1799
- || HMAC_Update(ctx_hmac_, first_block, 4) != 1
1800
- || HMAC_Update(ctx_hmac_, packet, packet_len) != 1
1801
- || HMAC_Final(ctx_hmac_, calc_mac, &outlen) != 1) {
1802
- r = kErrOpenSSL;
1803
- goto out;
1804
- }
1805
-
1806
- if (outlen != hmac_len_ || mac_len != hmac_actual_len_) {
1807
- r = kErrBadHMACLen;
1808
- goto out;
1809
- }
1810
-
1811
- // Compare MACs
1812
- if (CRYPTO_memcmp(mac, calc_mac, hmac_actual_len_)) {
1813
- r = kErrInvalidMAC;
1814
- goto out;
1815
- }
2009
+ if (is_etm_) {
2010
+ // `first_block` for ETM should just be the unencrypted packet length
2011
+ if (first_block_len != 4) {
2012
+ r = kErrBadBlockLen;
2013
+ goto out;
2014
+ }
2015
+
2016
+ // Decrypt packet
2017
+ if (EVP_DecryptUpdate(ctx_, packet, &outlen, packet, packet_len) != 1) {
2018
+ r = kErrOpenSSL;
2019
+ goto out;
2020
+ }
2021
+ if (static_cast<size_t>(outlen) != packet_len) {
2022
+ r = kErrPartialDecrypt;
2023
+ goto out;
1816
2024
  }
1817
2025
  }
1818
2026
 
@@ -1981,8 +2189,14 @@ out:
1981
2189
  }
1982
2190
 
1983
2191
  EVP_CIPHER_CTX* ctx_;
2192
+ #if REAL_OPENSSL_MAJOR >= 3
2193
+ EVP_MAC* mac_;
2194
+ EVP_MAC_CTX* mac_ctx_base_;
2195
+ size_t hmac_len_;
2196
+ #else
1984
2197
  HMAC_CTX* ctx_hmac_;
1985
2198
  unsigned int hmac_len_;
2199
+ #endif
1986
2200
  unsigned int hmac_actual_len_;
1987
2201
  uint8_t is_etm_;
1988
2202
  uint8_t is_stream_;
@@ -1991,6 +2205,63 @@ out:
1991
2205
 
1992
2206
 
1993
2207
  NAN_MODULE_INIT(init) {
2208
+ // These are needed because node-gyp (as of this writing) does not use the
2209
+ // proper (OpenSSL) system headers when node was built against a shared
2210
+ // version of OpenSSL. Usually this isn't an issue because OSes that build
2211
+ // node in this way typically use the same version of OpenSSL as was bundled
2212
+ // with node for a particular node version for the best compatibility. However
2213
+ // with the inclusion of OpenSSL 3.x in node v17.x, some OSes are still
2214
+ // linking with a shared OpenSSL 1.x, which can cause both compilation and
2215
+ // runtime errors because of changes in OpenSSL's code.
2216
+ //
2217
+ // For that reason, we need to make sure we need to resolve some specific
2218
+ // symbols at runtime to workaround these buggy situations.
2219
+ #ifdef _WIN32
2220
+ # define load_sym(name) GetProcAddress(GetModuleHandle(NULL), name)
2221
+ #else
2222
+ # define load_sym(name) dlsym(RTLD_DEFAULT, name)
2223
+ #endif
2224
+ if (!ctx_iv_len) {
2225
+ ctx_iv_len = reinterpret_cast<ctx_iv_len_func>(
2226
+ load_sym("EVP_CIPHER_CTX_get_iv_length")
2227
+ );
2228
+ if (!ctx_iv_len) {
2229
+ ctx_iv_len = reinterpret_cast<ctx_iv_len_func>(
2230
+ load_sym("EVP_CIPHER_CTX_iv_length")
2231
+ );
2232
+ }
2233
+ }
2234
+ if (!ctx_key_len) {
2235
+ ctx_key_len = reinterpret_cast<ctx_key_len_func>(
2236
+ load_sym("EVP_CIPHER_CTX_get_key_length")
2237
+ );
2238
+ if (!ctx_key_len) {
2239
+ ctx_key_len = reinterpret_cast<ctx_key_len_func>(
2240
+ load_sym("EVP_CIPHER_CTX_key_length")
2241
+ );
2242
+ }
2243
+ }
2244
+ if (!cipher_flags) {
2245
+ cipher_flags = reinterpret_cast<cipher_flags_func>(
2246
+ load_sym("EVP_CIPHER_get_flags")
2247
+ );
2248
+ if (!cipher_flags) {
2249
+ cipher_flags = reinterpret_cast<cipher_flags_func>(
2250
+ load_sym("EVP_CIPHER_flags")
2251
+ );
2252
+ }
2253
+ }
2254
+ if (!ctx_get_block_size) {
2255
+ ctx_get_block_size = reinterpret_cast<ctx_get_block_size_func>(
2256
+ load_sym("EVP_CIPHER_CTX_get_block_size")
2257
+ );
2258
+ if (!ctx_get_block_size) {
2259
+ ctx_get_block_size = reinterpret_cast<ctx_get_block_size_func>(
2260
+ load_sym("EVP_CIPHER_CTX_block_size")
2261
+ );
2262
+ }
2263
+ }
2264
+
1994
2265
  ChaChaPolyCipher::Init(target);
1995
2266
  AESGCMCipher::Init(target);
1996
2267
  GenericCipher::Init(target);
@@ -2000,4 +2271,6 @@ NAN_MODULE_INIT(init) {
2000
2271
  GenericDecipher::Init(target);
2001
2272
  }
2002
2273
 
2003
- NODE_MODULE(sshcrypto, init)
2274
+ DISABLE_WCAST_FUNCTION_TYPE
2275
+ NAN_MODULE_WORKER_ENABLED(sshcrypto, init)
2276
+ DISABLE_WCAST_FUNCTION_TYPE_END
@@ -595,6 +595,8 @@ OpenSSH_Private.prototype = BaseKey;
595
595
  } else {
596
596
  ret = [];
597
597
  }
598
+ if (ret instanceof Error)
599
+ return ret;
598
600
  // This will need to change if/when OpenSSH ever starts storing multiple
599
601
  // keys in their key files
600
602
  return ret[0];
@@ -171,7 +171,7 @@ module.exports = {
171
171
  doFatalError: (protocol, msg, level, reason) => {
172
172
  let err;
173
173
  if (DISCONNECT_REASON === undefined)
174
- ({ DISCONNECT_REASON } = require('./utils.js'));
174
+ ({ DISCONNECT_REASON } = require('./constants.js'));
175
175
  if (msg instanceof Error) {
176
176
  // doFatalError(protocol, err[, reason])
177
177
  err = msg;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electerm/ssh2",
3
- "version": "1.5.0",
3
+ "version": "1.11.0",
4
4
  "author": "Brian White <mscdex@mscdex.net>",
5
5
  "description": "SSH2 client and server modules written in pure JavaScript for node.js",
6
6
  "main": "./lib/index.js",
@@ -12,13 +12,9 @@
12
12
  "bcrypt-pbkdf": "^1.0.2"
13
13
  },
14
14
  "devDependencies": {
15
- "@mscdex/eslint-config": "^1.0.0",
15
+ "@mscdex/eslint-config": "^1.1.0",
16
16
  "eslint": "^7.0.0"
17
17
  },
18
- "peerDependencies": {
19
- "cpu-features": "0.0.2",
20
- "nan": "^2.15.0"
21
- },
22
18
  "scripts": {
23
19
  "install": "node install.js",
24
20
  "rebuild": "node install.js",