bdy 1.23.6-dev → 1.23.7-dev

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.
Files changed (205) hide show
  1. package/distTs/package.json +10 -2
  2. package/distTs/src/agent/linux.js +53 -3
  3. package/distTs/src/agent/manager.js +3 -6
  4. package/distTs/src/agent/osx.js +51 -3
  5. package/distTs/src/agent/system.js +400 -21
  6. package/distTs/src/agent/windows.js +4 -7
  7. package/distTs/src/command/agent/debug.js +2 -2
  8. package/distTs/src/command/agent/install.js +37 -10
  9. package/distTs/src/command/agent/restart.js +2 -2
  10. package/distTs/src/command/agent/run.js +3 -0
  11. package/distTs/src/command/agent/start.js +2 -2
  12. package/distTs/src/command/agent/status.js +19 -0
  13. package/distTs/src/command/agent/stop.js +2 -2
  14. package/distTs/src/command/agent/uninstall.js +5 -8
  15. package/distTs/src/command/agent/update.js +2 -2
  16. package/distTs/src/command/artifact/publish.js +3 -1
  17. package/distTs/src/command/version.js +13 -5
  18. package/distTs/src/logger.js +40 -4
  19. package/distTs/src/texts.js +35 -19
  20. package/distTs/src/utils.js +98 -3
  21. package/node_modules/asn1/Jenkinsfile +65 -0
  22. package/node_modules/asn1/LICENSE +19 -0
  23. package/node_modules/asn1/README.md +50 -0
  24. package/node_modules/asn1/lib/ber/errors.js +13 -0
  25. package/node_modules/asn1/lib/ber/index.js +27 -0
  26. package/node_modules/asn1/lib/ber/reader.js +262 -0
  27. package/node_modules/asn1/lib/ber/types.js +36 -0
  28. package/node_modules/asn1/lib/ber/writer.js +317 -0
  29. package/node_modules/asn1/lib/index.js +20 -0
  30. package/node_modules/asn1/package.json +31 -0
  31. package/node_modules/bcrypt-pbkdf/CONTRIBUTING.md +13 -0
  32. package/node_modules/bcrypt-pbkdf/LICENSE +66 -0
  33. package/node_modules/bcrypt-pbkdf/README.md +45 -0
  34. package/node_modules/bcrypt-pbkdf/index.js +556 -0
  35. package/node_modules/bcrypt-pbkdf/package.json +15 -0
  36. package/node_modules/safer-buffer/LICENSE +21 -0
  37. package/node_modules/safer-buffer/Porting-Buffer.md +268 -0
  38. package/node_modules/safer-buffer/Readme.md +156 -0
  39. package/node_modules/safer-buffer/dangerous.js +58 -0
  40. package/node_modules/safer-buffer/package.json +34 -0
  41. package/node_modules/safer-buffer/safer.js +77 -0
  42. package/node_modules/safer-buffer/tests.js +406 -0
  43. package/node_modules/ssh2/.eslintignore +4 -0
  44. package/node_modules/ssh2/.eslintrc.js +5 -0
  45. package/node_modules/ssh2/.github/workflows/ci.yml +110 -0
  46. package/node_modules/ssh2/.github/workflows/lint.yml +27 -0
  47. package/node_modules/ssh2/LICENSE +19 -0
  48. package/node_modules/ssh2/README.md +1529 -0
  49. package/node_modules/ssh2/SFTP.md +413 -0
  50. package/node_modules/ssh2/examples/server-chat.js +238 -0
  51. package/node_modules/ssh2/examples/sftp-server-download-only.js +134 -0
  52. package/node_modules/ssh2/install.js +27 -0
  53. package/node_modules/ssh2/lib/Channel.js +295 -0
  54. package/node_modules/ssh2/lib/agent.js +1123 -0
  55. package/node_modules/ssh2/lib/client.js +2176 -0
  56. package/node_modules/ssh2/lib/http-agents.js +84 -0
  57. package/node_modules/ssh2/lib/index.js +44 -0
  58. package/node_modules/ssh2/lib/keygen.js +582 -0
  59. package/node_modules/ssh2/lib/protocol/Protocol.js +2136 -0
  60. package/node_modules/ssh2/lib/protocol/SFTP.js +4052 -0
  61. package/node_modules/ssh2/lib/protocol/constants.js +356 -0
  62. package/node_modules/ssh2/lib/protocol/crypto/binding.gyp +23 -0
  63. package/node_modules/ssh2/lib/protocol/crypto/poly1305.js +43 -0
  64. package/node_modules/ssh2/lib/protocol/crypto/src/binding.cc +2300 -0
  65. package/node_modules/ssh2/lib/protocol/crypto.js +1602 -0
  66. package/node_modules/ssh2/lib/protocol/handlers.js +16 -0
  67. package/node_modules/ssh2/lib/protocol/handlers.misc.js +1285 -0
  68. package/node_modules/ssh2/lib/protocol/kex.js +1908 -0
  69. package/node_modules/ssh2/lib/protocol/keyParser.js +1484 -0
  70. package/node_modules/ssh2/lib/protocol/node-fs-compat.js +115 -0
  71. package/node_modules/ssh2/lib/protocol/utils.js +356 -0
  72. package/node_modules/ssh2/lib/protocol/zlib.js +255 -0
  73. package/node_modules/ssh2/lib/server.js +1380 -0
  74. package/node_modules/ssh2/lib/utils.js +336 -0
  75. package/node_modules/ssh2/package.json +49 -0
  76. package/node_modules/ssh2/test/common.js +316 -0
  77. package/node_modules/ssh2/test/fixtures/bad_rsa_private_key +26 -0
  78. package/node_modules/ssh2/test/fixtures/https_cert.pem +33 -0
  79. package/node_modules/ssh2/test/fixtures/https_key.pem +52 -0
  80. package/node_modules/ssh2/test/fixtures/id_dsa +12 -0
  81. package/node_modules/ssh2/test/fixtures/id_ecdsa +5 -0
  82. package/node_modules/ssh2/test/fixtures/id_rsa +15 -0
  83. package/node_modules/ssh2/test/fixtures/id_rsa.ppk +26 -0
  84. package/node_modules/ssh2/test/fixtures/id_rsa_enc +30 -0
  85. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa +21 -0
  86. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.pub +1 -0
  87. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.pub.result +7 -0
  88. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.result +7 -0
  89. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc +22 -0
  90. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.pub +1 -0
  91. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.pub.result +7 -0
  92. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.result +7 -0
  93. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm +23 -0
  94. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.pub +1 -0
  95. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.pub.result +7 -0
  96. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.result +7 -0
  97. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa +9 -0
  98. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.pub +1 -0
  99. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.pub.result +7 -0
  100. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.result +7 -0
  101. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc +10 -0
  102. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.pub +1 -0
  103. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.pub.result +8 -0
  104. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.result +7 -0
  105. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm +10 -0
  106. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.pub +1 -0
  107. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.pub.result +8 -0
  108. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.result +7 -0
  109. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519 +7 -0
  110. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.pub +1 -0
  111. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.pub.result +7 -0
  112. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.result +7 -0
  113. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa +27 -0
  114. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.pub +1 -0
  115. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.pub.result +7 -0
  116. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.result +7 -0
  117. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc +28 -0
  118. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.pub +1 -0
  119. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.pub.result +8 -0
  120. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.result +7 -0
  121. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm +29 -0
  122. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.pub +1 -0
  123. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.pub.result +8 -0
  124. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.result +7 -0
  125. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa +12 -0
  126. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.pub +1 -0
  127. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.pub.result +7 -0
  128. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.result +7 -0
  129. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc +15 -0
  130. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.pub +1 -0
  131. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.pub.result +8 -0
  132. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.result +7 -0
  133. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa +5 -0
  134. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.pub +1 -0
  135. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.pub.result +7 -0
  136. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.result +7 -0
  137. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc +8 -0
  138. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.pub +1 -0
  139. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.pub.result +8 -0
  140. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.result +7 -0
  141. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa +27 -0
  142. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.pub +1 -0
  143. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.pub.result +7 -0
  144. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.result +7 -0
  145. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc +30 -0
  146. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.pub +1 -0
  147. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.pub.result +8 -0
  148. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.result +7 -0
  149. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256 +54 -0
  150. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.pub +1 -0
  151. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.pub.result +6 -0
  152. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.result +6 -0
  153. package/node_modules/ssh2/test/fixtures/keyParser/ppk_dsa_enc +17 -0
  154. package/node_modules/ssh2/test/fixtures/keyParser/ppk_dsa_enc.result +7 -0
  155. package/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa +26 -0
  156. package/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa.result +7 -0
  157. package/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa_enc +18 -0
  158. package/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa_enc.result +7 -0
  159. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa.pub +9 -0
  160. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa.pub.result +7 -0
  161. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa2.pub +10 -0
  162. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa2.pub.result +7 -0
  163. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa3.pub +11 -0
  164. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa3.pub.result +7 -0
  165. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa4.pub +11 -0
  166. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa4.pub.result +7 -0
  167. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa5.pub +8 -0
  168. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa5.pub.result +7 -0
  169. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa6.pub +13 -0
  170. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa6.pub.result +7 -0
  171. package/node_modules/ssh2/test/fixtures/openssh_new_rsa +27 -0
  172. package/node_modules/ssh2/test/fixtures/ssh_host_dsa_key +12 -0
  173. package/node_modules/ssh2/test/fixtures/ssh_host_ecdsa_key +5 -0
  174. package/node_modules/ssh2/test/fixtures/ssh_host_rsa_key +15 -0
  175. package/node_modules/ssh2/test/test-exec.js +578 -0
  176. package/node_modules/ssh2/test/test-integration-openssh.js +486 -0
  177. package/node_modules/ssh2/test/test-keygen.js +60 -0
  178. package/node_modules/ssh2/test/test-misc-client-server.js +1460 -0
  179. package/node_modules/ssh2/test/test-openssh.js +261 -0
  180. package/node_modules/ssh2/test/test-protocol-crypto.js +631 -0
  181. package/node_modules/ssh2/test/test-protocol-keyparser.js +177 -0
  182. package/node_modules/ssh2/test/test-server-hostkeys.js +138 -0
  183. package/node_modules/ssh2/test/test-sftp.js +842 -0
  184. package/node_modules/ssh2/test/test-shell.js +109 -0
  185. package/node_modules/ssh2/test/test-userauth-agent-openssh.js +110 -0
  186. package/node_modules/ssh2/test/test-userauth-agent.js +171 -0
  187. package/node_modules/ssh2/test/test-userauth.js +611 -0
  188. package/node_modules/ssh2/test/test-worker-imports.js +25 -0
  189. package/node_modules/ssh2/test/test.js +20 -0
  190. package/node_modules/ssh2/util/build_pagent.bat +2 -0
  191. package/node_modules/ssh2/util/pagent.c +88 -0
  192. package/node_modules/ssh2/util/pagent.exe +0 -0
  193. package/node_modules/tweetnacl/.npmignore +4 -0
  194. package/node_modules/tweetnacl/AUTHORS.md +28 -0
  195. package/node_modules/tweetnacl/CHANGELOG.md +221 -0
  196. package/node_modules/tweetnacl/LICENSE +24 -0
  197. package/node_modules/tweetnacl/PULL_REQUEST_TEMPLATE.md +20 -0
  198. package/node_modules/tweetnacl/README.md +459 -0
  199. package/node_modules/tweetnacl/nacl-fast.js +2388 -0
  200. package/node_modules/tweetnacl/nacl-fast.min.js +2 -0
  201. package/node_modules/tweetnacl/nacl.d.ts +98 -0
  202. package/node_modules/tweetnacl/nacl.js +1175 -0
  203. package/node_modules/tweetnacl/nacl.min.js +1 -0
  204. package/node_modules/tweetnacl/package.json +58 -0
  205. package/package.json +10 -2
@@ -0,0 +1,1484 @@
1
+ // TODO:
2
+ // * utilize `crypto.create(Private|Public)Key()` and `keyObject.export()`
3
+ // * handle multi-line header values (OpenSSH)?
4
+ // * more thorough validation?
5
+ 'use strict';
6
+
7
+ const {
8
+ createDecipheriv,
9
+ createECDH,
10
+ createHash,
11
+ createHmac,
12
+ createSign,
13
+ createVerify,
14
+ getCiphers,
15
+ sign: sign_,
16
+ verify: verify_,
17
+ } = require('crypto');
18
+ const supportedOpenSSLCiphers = getCiphers();
19
+
20
+ const { Ber } = require('asn1');
21
+ const bcrypt_pbkdf = require('bcrypt-pbkdf').pbkdf;
22
+
23
+ const { CIPHER_INFO } = require('./crypto.js');
24
+ const { eddsaSupported, SUPPORTED_CIPHER } = require('./constants.js');
25
+ const {
26
+ bufferSlice,
27
+ makeBufferParser,
28
+ readString,
29
+ readUInt32BE,
30
+ writeUInt32BE,
31
+ } = require('./utils.js');
32
+
33
+ const SYM_HASH_ALGO = Symbol('Hash Algorithm');
34
+ const SYM_PRIV_PEM = Symbol('Private key PEM');
35
+ const SYM_PUB_PEM = Symbol('Public key PEM');
36
+ const SYM_PUB_SSH = Symbol('Public key SSH');
37
+ const SYM_DECRYPTED = Symbol('Decrypted Key');
38
+
39
+ // Create OpenSSL cipher name -> SSH cipher name conversion table
40
+ const CIPHER_INFO_OPENSSL = Object.create(null);
41
+ {
42
+ const keys = Object.keys(CIPHER_INFO);
43
+ for (let i = 0; i < keys.length; ++i) {
44
+ const cipherName = CIPHER_INFO[keys[i]].sslName;
45
+ if (!cipherName || CIPHER_INFO_OPENSSL[cipherName])
46
+ continue;
47
+ CIPHER_INFO_OPENSSL[cipherName] = CIPHER_INFO[keys[i]];
48
+ }
49
+ }
50
+
51
+ const binaryKeyParser = makeBufferParser();
52
+
53
+ function makePEM(type, data) {
54
+ data = data.base64Slice(0, data.length);
55
+ let formatted = data.replace(/.{64}/g, '$&\n');
56
+ if (data.length & 63)
57
+ formatted += '\n';
58
+ return `-----BEGIN ${type} KEY-----\n${formatted}-----END ${type} KEY-----`;
59
+ }
60
+
61
+ function combineBuffers(buf1, buf2) {
62
+ const result = Buffer.allocUnsafe(buf1.length + buf2.length);
63
+ result.set(buf1, 0);
64
+ result.set(buf2, buf1.length);
65
+ return result;
66
+ }
67
+
68
+ function skipFields(buf, nfields) {
69
+ const bufLen = buf.length;
70
+ let pos = (buf._pos || 0);
71
+ for (let i = 0; i < nfields; ++i) {
72
+ const left = (bufLen - pos);
73
+ if (pos >= bufLen || left < 4)
74
+ return false;
75
+ const len = readUInt32BE(buf, pos);
76
+ if (left < 4 + len)
77
+ return false;
78
+ pos += 4 + len;
79
+ }
80
+ buf._pos = pos;
81
+ return true;
82
+ }
83
+
84
+ function genOpenSSLRSAPub(n, e) {
85
+ const asnWriter = new Ber.Writer();
86
+ asnWriter.startSequence();
87
+ // algorithm
88
+ asnWriter.startSequence();
89
+ asnWriter.writeOID('1.2.840.113549.1.1.1'); // rsaEncryption
90
+ // algorithm parameters (RSA has none)
91
+ asnWriter.writeNull();
92
+ asnWriter.endSequence();
93
+
94
+ // subjectPublicKey
95
+ asnWriter.startSequence(Ber.BitString);
96
+ asnWriter.writeByte(0x00);
97
+ asnWriter.startSequence();
98
+ asnWriter.writeBuffer(n, Ber.Integer);
99
+ asnWriter.writeBuffer(e, Ber.Integer);
100
+ asnWriter.endSequence();
101
+ asnWriter.endSequence();
102
+ asnWriter.endSequence();
103
+ return makePEM('PUBLIC', asnWriter.buffer);
104
+ }
105
+
106
+ function genOpenSSHRSAPub(n, e) {
107
+ const publicKey = Buffer.allocUnsafe(4 + 7 + 4 + e.length + 4 + n.length);
108
+
109
+ writeUInt32BE(publicKey, 7, 0);
110
+ publicKey.utf8Write('ssh-rsa', 4, 7);
111
+
112
+ let i = 4 + 7;
113
+ writeUInt32BE(publicKey, e.length, i);
114
+ publicKey.set(e, i += 4);
115
+
116
+ writeUInt32BE(publicKey, n.length, i += e.length);
117
+ publicKey.set(n, i + 4);
118
+
119
+ return publicKey;
120
+ }
121
+
122
+ const genOpenSSLRSAPriv = (() => {
123
+ function genRSAASN1Buf(n, e, d, p, q, dmp1, dmq1, iqmp) {
124
+ const asnWriter = new Ber.Writer();
125
+ asnWriter.startSequence();
126
+ asnWriter.writeInt(0x00, Ber.Integer);
127
+ asnWriter.writeBuffer(n, Ber.Integer);
128
+ asnWriter.writeBuffer(e, Ber.Integer);
129
+ asnWriter.writeBuffer(d, Ber.Integer);
130
+ asnWriter.writeBuffer(p, Ber.Integer);
131
+ asnWriter.writeBuffer(q, Ber.Integer);
132
+ asnWriter.writeBuffer(dmp1, Ber.Integer);
133
+ asnWriter.writeBuffer(dmq1, Ber.Integer);
134
+ asnWriter.writeBuffer(iqmp, Ber.Integer);
135
+ asnWriter.endSequence();
136
+ return asnWriter.buffer;
137
+ }
138
+
139
+ function bigIntFromBuffer(buf) {
140
+ return BigInt(`0x${buf.hexSlice(0, buf.length)}`);
141
+ }
142
+
143
+ function bigIntToBuffer(bn) {
144
+ let hex = bn.toString(16);
145
+ if ((hex.length & 1) !== 0) {
146
+ hex = `0${hex}`;
147
+ } else {
148
+ const sigbit = hex.charCodeAt(0);
149
+ // BER/DER integers require leading zero byte to denote a positive value
150
+ // when first byte >= 0x80
151
+ if (sigbit === 56/* '8' */
152
+ || sigbit === 57/* '9' */
153
+ || (sigbit >= 97/* 'a' */ && sigbit <= 102/* 'f' */)) {
154
+ hex = `00${hex}`;
155
+ }
156
+ }
157
+ return Buffer.from(hex, 'hex');
158
+ }
159
+
160
+ return function genOpenSSLRSAPriv(n, e, d, iqmp, p, q) {
161
+ const bn_d = bigIntFromBuffer(d);
162
+ const dmp1 = bigIntToBuffer(bn_d % (bigIntFromBuffer(p) - 1n));
163
+ const dmq1 = bigIntToBuffer(bn_d % (bigIntFromBuffer(q) - 1n));
164
+ return makePEM('RSA PRIVATE',
165
+ genRSAASN1Buf(n, e, d, p, q, dmp1, dmq1, iqmp));
166
+ };
167
+ })();
168
+
169
+ function genOpenSSLDSAPub(p, q, g, y) {
170
+ const asnWriter = new Ber.Writer();
171
+ asnWriter.startSequence();
172
+ // algorithm
173
+ asnWriter.startSequence();
174
+ asnWriter.writeOID('1.2.840.10040.4.1'); // id-dsa
175
+ // algorithm parameters
176
+ asnWriter.startSequence();
177
+ asnWriter.writeBuffer(p, Ber.Integer);
178
+ asnWriter.writeBuffer(q, Ber.Integer);
179
+ asnWriter.writeBuffer(g, Ber.Integer);
180
+ asnWriter.endSequence();
181
+ asnWriter.endSequence();
182
+
183
+ // subjectPublicKey
184
+ asnWriter.startSequence(Ber.BitString);
185
+ asnWriter.writeByte(0x00);
186
+ asnWriter.writeBuffer(y, Ber.Integer);
187
+ asnWriter.endSequence();
188
+ asnWriter.endSequence();
189
+ return makePEM('PUBLIC', asnWriter.buffer);
190
+ }
191
+
192
+ function genOpenSSHDSAPub(p, q, g, y) {
193
+ const publicKey = Buffer.allocUnsafe(
194
+ 4 + 7 + 4 + p.length + 4 + q.length + 4 + g.length + 4 + y.length
195
+ );
196
+
197
+ writeUInt32BE(publicKey, 7, 0);
198
+ publicKey.utf8Write('ssh-dss', 4, 7);
199
+
200
+ let i = 4 + 7;
201
+ writeUInt32BE(publicKey, p.length, i);
202
+ publicKey.set(p, i += 4);
203
+
204
+ writeUInt32BE(publicKey, q.length, i += p.length);
205
+ publicKey.set(q, i += 4);
206
+
207
+ writeUInt32BE(publicKey, g.length, i += q.length);
208
+ publicKey.set(g, i += 4);
209
+
210
+ writeUInt32BE(publicKey, y.length, i += g.length);
211
+ publicKey.set(y, i + 4);
212
+
213
+ return publicKey;
214
+ }
215
+
216
+ function genOpenSSLDSAPriv(p, q, g, y, x) {
217
+ const asnWriter = new Ber.Writer();
218
+ asnWriter.startSequence();
219
+ asnWriter.writeInt(0x00, Ber.Integer);
220
+ asnWriter.writeBuffer(p, Ber.Integer);
221
+ asnWriter.writeBuffer(q, Ber.Integer);
222
+ asnWriter.writeBuffer(g, Ber.Integer);
223
+ asnWriter.writeBuffer(y, Ber.Integer);
224
+ asnWriter.writeBuffer(x, Ber.Integer);
225
+ asnWriter.endSequence();
226
+ return makePEM('DSA PRIVATE', asnWriter.buffer);
227
+ }
228
+
229
+ function genOpenSSLEdPub(pub) {
230
+ const asnWriter = new Ber.Writer();
231
+ asnWriter.startSequence();
232
+ // algorithm
233
+ asnWriter.startSequence();
234
+ asnWriter.writeOID('1.3.101.112'); // id-Ed25519
235
+ asnWriter.endSequence();
236
+
237
+ // PublicKey
238
+ asnWriter.startSequence(Ber.BitString);
239
+ asnWriter.writeByte(0x00);
240
+ // XXX: hack to write a raw buffer without a tag -- yuck
241
+ asnWriter._ensure(pub.length);
242
+ asnWriter._buf.set(pub, asnWriter._offset);
243
+ asnWriter._offset += pub.length;
244
+ asnWriter.endSequence();
245
+ asnWriter.endSequence();
246
+ return makePEM('PUBLIC', asnWriter.buffer);
247
+ }
248
+
249
+ function genOpenSSHEdPub(pub) {
250
+ const publicKey = Buffer.allocUnsafe(4 + 11 + 4 + pub.length);
251
+
252
+ writeUInt32BE(publicKey, 11, 0);
253
+ publicKey.utf8Write('ssh-ed25519', 4, 11);
254
+
255
+ writeUInt32BE(publicKey, pub.length, 15);
256
+ publicKey.set(pub, 19);
257
+
258
+ return publicKey;
259
+ }
260
+
261
+ function genOpenSSLEdPriv(priv) {
262
+ const asnWriter = new Ber.Writer();
263
+ asnWriter.startSequence();
264
+ // version
265
+ asnWriter.writeInt(0x00, Ber.Integer);
266
+
267
+ // algorithm
268
+ asnWriter.startSequence();
269
+ asnWriter.writeOID('1.3.101.112'); // id-Ed25519
270
+ asnWriter.endSequence();
271
+
272
+ // PrivateKey
273
+ asnWriter.startSequence(Ber.OctetString);
274
+ asnWriter.writeBuffer(priv, Ber.OctetString);
275
+ asnWriter.endSequence();
276
+ asnWriter.endSequence();
277
+ return makePEM('PRIVATE', asnWriter.buffer);
278
+ }
279
+
280
+ function genOpenSSLECDSAPub(oid, Q) {
281
+ const asnWriter = new Ber.Writer();
282
+ asnWriter.startSequence();
283
+ // algorithm
284
+ asnWriter.startSequence();
285
+ asnWriter.writeOID('1.2.840.10045.2.1'); // id-ecPublicKey
286
+ // algorithm parameters (namedCurve)
287
+ asnWriter.writeOID(oid);
288
+ asnWriter.endSequence();
289
+
290
+ // subjectPublicKey
291
+ asnWriter.startSequence(Ber.BitString);
292
+ asnWriter.writeByte(0x00);
293
+ // XXX: hack to write a raw buffer without a tag -- yuck
294
+ asnWriter._ensure(Q.length);
295
+ asnWriter._buf.set(Q, asnWriter._offset);
296
+ asnWriter._offset += Q.length;
297
+ // end hack
298
+ asnWriter.endSequence();
299
+ asnWriter.endSequence();
300
+ return makePEM('PUBLIC', asnWriter.buffer);
301
+ }
302
+
303
+ function genOpenSSHECDSAPub(oid, Q) {
304
+ let curveName;
305
+ switch (oid) {
306
+ case '1.2.840.10045.3.1.7':
307
+ // prime256v1/secp256r1
308
+ curveName = 'nistp256';
309
+ break;
310
+ case '1.3.132.0.34':
311
+ // secp384r1
312
+ curveName = 'nistp384';
313
+ break;
314
+ case '1.3.132.0.35':
315
+ // secp521r1
316
+ curveName = 'nistp521';
317
+ break;
318
+ default:
319
+ return;
320
+ }
321
+
322
+ const publicKey = Buffer.allocUnsafe(4 + 19 + 4 + 8 + 4 + Q.length);
323
+
324
+ writeUInt32BE(publicKey, 19, 0);
325
+ publicKey.utf8Write(`ecdsa-sha2-${curveName}`, 4, 19);
326
+
327
+ writeUInt32BE(publicKey, 8, 23);
328
+ publicKey.utf8Write(curveName, 27, 8);
329
+
330
+ writeUInt32BE(publicKey, Q.length, 35);
331
+ publicKey.set(Q, 39);
332
+
333
+ return publicKey;
334
+ }
335
+
336
+ function genOpenSSLECDSAPriv(oid, pub, priv) {
337
+ const asnWriter = new Ber.Writer();
338
+ asnWriter.startSequence();
339
+ // version
340
+ asnWriter.writeInt(0x01, Ber.Integer);
341
+ // privateKey
342
+ asnWriter.writeBuffer(priv, Ber.OctetString);
343
+ // parameters (optional)
344
+ asnWriter.startSequence(0xA0);
345
+ asnWriter.writeOID(oid);
346
+ asnWriter.endSequence();
347
+ // publicKey (optional)
348
+ asnWriter.startSequence(0xA1);
349
+ asnWriter.startSequence(Ber.BitString);
350
+ asnWriter.writeByte(0x00);
351
+ // XXX: hack to write a raw buffer without a tag -- yuck
352
+ asnWriter._ensure(pub.length);
353
+ asnWriter._buf.set(pub, asnWriter._offset);
354
+ asnWriter._offset += pub.length;
355
+ // end hack
356
+ asnWriter.endSequence();
357
+ asnWriter.endSequence();
358
+ asnWriter.endSequence();
359
+ return makePEM('EC PRIVATE', asnWriter.buffer);
360
+ }
361
+
362
+ function genOpenSSLECDSAPubFromPriv(curveName, priv) {
363
+ const tempECDH = createECDH(curveName);
364
+ tempECDH.setPrivateKey(priv);
365
+ return tempECDH.getPublicKey();
366
+ }
367
+
368
+ const BaseKey = {
369
+ sign: (() => {
370
+ if (typeof sign_ === 'function') {
371
+ return function sign(data, algo) {
372
+ const pem = this[SYM_PRIV_PEM];
373
+ if (pem === null)
374
+ return new Error('No private key available');
375
+ if (!algo || typeof algo !== 'string')
376
+ algo = this[SYM_HASH_ALGO];
377
+ try {
378
+ return sign_(algo, data, pem);
379
+ } catch (ex) {
380
+ return ex;
381
+ }
382
+ };
383
+ }
384
+ return function sign(data, algo) {
385
+ const pem = this[SYM_PRIV_PEM];
386
+ if (pem === null)
387
+ return new Error('No private key available');
388
+ if (!algo || typeof algo !== 'string')
389
+ algo = this[SYM_HASH_ALGO];
390
+ const signature = createSign(algo);
391
+ signature.update(data);
392
+ try {
393
+ return signature.sign(pem);
394
+ } catch (ex) {
395
+ return ex;
396
+ }
397
+ };
398
+ })(),
399
+ verify: (() => {
400
+ if (typeof verify_ === 'function') {
401
+ return function verify(data, signature, algo) {
402
+ const pem = this[SYM_PUB_PEM];
403
+ if (pem === null)
404
+ return new Error('No public key available');
405
+ if (!algo || typeof algo !== 'string')
406
+ algo = this[SYM_HASH_ALGO];
407
+ try {
408
+ return verify_(algo, data, pem, signature);
409
+ } catch (ex) {
410
+ return ex;
411
+ }
412
+ };
413
+ }
414
+ return function verify(data, signature, algo) {
415
+ const pem = this[SYM_PUB_PEM];
416
+ if (pem === null)
417
+ return new Error('No public key available');
418
+ if (!algo || typeof algo !== 'string')
419
+ algo = this[SYM_HASH_ALGO];
420
+ const verifier = createVerify(algo);
421
+ verifier.update(data);
422
+ try {
423
+ return verifier.verify(pem, signature);
424
+ } catch (ex) {
425
+ return ex;
426
+ }
427
+ };
428
+ })(),
429
+ isPrivateKey: function isPrivateKey() {
430
+ return (this[SYM_PRIV_PEM] !== null);
431
+ },
432
+ getPrivatePEM: function getPrivatePEM() {
433
+ return this[SYM_PRIV_PEM];
434
+ },
435
+ getPublicPEM: function getPublicPEM() {
436
+ return this[SYM_PUB_PEM];
437
+ },
438
+ getPublicSSH: function getPublicSSH() {
439
+ return this[SYM_PUB_SSH];
440
+ },
441
+ equals: function equals(key) {
442
+ const parsed = parseKey(key);
443
+ if (parsed instanceof Error)
444
+ return false;
445
+ return (
446
+ this.type === parsed.type
447
+ && this[SYM_PRIV_PEM] === parsed[SYM_PRIV_PEM]
448
+ && this[SYM_PUB_PEM] === parsed[SYM_PUB_PEM]
449
+ && this[SYM_PUB_SSH].equals(parsed[SYM_PUB_SSH])
450
+ );
451
+ },
452
+ };
453
+
454
+
455
+ function OpenSSH_Private(type, comment, privPEM, pubPEM, pubSSH, algo,
456
+ decrypted) {
457
+ this.type = type;
458
+ this.comment = comment;
459
+ this[SYM_PRIV_PEM] = privPEM;
460
+ this[SYM_PUB_PEM] = pubPEM;
461
+ this[SYM_PUB_SSH] = pubSSH;
462
+ this[SYM_HASH_ALGO] = algo;
463
+ this[SYM_DECRYPTED] = decrypted;
464
+ }
465
+ OpenSSH_Private.prototype = BaseKey;
466
+ {
467
+ const regexp = /^-----BEGIN OPENSSH PRIVATE KEY-----(?:\r\n|\n)([\s\S]+)(?:\r\n|\n)-----END OPENSSH PRIVATE KEY-----$/;
468
+ OpenSSH_Private.parse = (str, passphrase) => {
469
+ const m = regexp.exec(str);
470
+ if (m === null)
471
+ return null;
472
+ let ret;
473
+ const data = Buffer.from(m[1], 'base64');
474
+ if (data.length < 31) // magic (+ magic null term.) + minimum field lengths
475
+ return new Error('Malformed OpenSSH private key');
476
+ const magic = data.utf8Slice(0, 15);
477
+ if (magic !== 'openssh-key-v1\0')
478
+ return new Error(`Unsupported OpenSSH key magic: ${magic}`);
479
+
480
+ const cipherName = readString(data, 15, true);
481
+ if (cipherName === undefined)
482
+ return new Error('Malformed OpenSSH private key');
483
+ if (cipherName !== 'none' && SUPPORTED_CIPHER.indexOf(cipherName) === -1)
484
+ return new Error(`Unsupported cipher for OpenSSH key: ${cipherName}`);
485
+
486
+ const kdfName = readString(data, data._pos, true);
487
+ if (kdfName === undefined)
488
+ return new Error('Malformed OpenSSH private key');
489
+ if (kdfName !== 'none') {
490
+ if (cipherName === 'none')
491
+ return new Error('Malformed OpenSSH private key');
492
+ if (kdfName !== 'bcrypt')
493
+ return new Error(`Unsupported kdf name for OpenSSH key: ${kdfName}`);
494
+ if (!passphrase) {
495
+ return new Error(
496
+ 'Encrypted private OpenSSH key detected, but no passphrase given'
497
+ );
498
+ }
499
+ } else if (cipherName !== 'none') {
500
+ return new Error('Malformed OpenSSH private key');
501
+ }
502
+
503
+ let encInfo;
504
+ let cipherKey;
505
+ let cipherIV;
506
+ if (cipherName !== 'none')
507
+ encInfo = CIPHER_INFO[cipherName];
508
+ const kdfOptions = readString(data, data._pos);
509
+ if (kdfOptions === undefined)
510
+ return new Error('Malformed OpenSSH private key');
511
+ if (kdfOptions.length) {
512
+ switch (kdfName) {
513
+ case 'none':
514
+ return new Error('Malformed OpenSSH private key');
515
+ case 'bcrypt': {
516
+ /*
517
+ string salt
518
+ uint32 rounds
519
+ */
520
+ const salt = readString(kdfOptions, 0);
521
+ if (salt === undefined || kdfOptions._pos + 4 > kdfOptions.length)
522
+ return new Error('Malformed OpenSSH private key');
523
+ const rounds = readUInt32BE(kdfOptions, kdfOptions._pos);
524
+ const gen = Buffer.allocUnsafe(encInfo.keyLen + encInfo.ivLen);
525
+ const r = bcrypt_pbkdf(passphrase,
526
+ passphrase.length,
527
+ salt,
528
+ salt.length,
529
+ gen,
530
+ gen.length,
531
+ rounds);
532
+ if (r !== 0)
533
+ return new Error('Failed to generate information to decrypt key');
534
+ cipherKey = bufferSlice(gen, 0, encInfo.keyLen);
535
+ cipherIV = bufferSlice(gen, encInfo.keyLen, gen.length);
536
+ break;
537
+ }
538
+ }
539
+ } else if (kdfName !== 'none') {
540
+ return new Error('Malformed OpenSSH private key');
541
+ }
542
+
543
+ if (data._pos + 3 >= data.length)
544
+ return new Error('Malformed OpenSSH private key');
545
+ const keyCount = readUInt32BE(data, data._pos);
546
+ data._pos += 4;
547
+
548
+ if (keyCount > 0) {
549
+ // TODO: place sensible limit on max `keyCount`
550
+
551
+ // Read public keys first
552
+ for (let i = 0; i < keyCount; ++i) {
553
+ const pubData = readString(data, data._pos);
554
+ if (pubData === undefined)
555
+ return new Error('Malformed OpenSSH private key');
556
+ const type = readString(pubData, 0, true);
557
+ if (type === undefined)
558
+ return new Error('Malformed OpenSSH private key');
559
+ }
560
+
561
+ let privBlob = readString(data, data._pos);
562
+ if (privBlob === undefined)
563
+ return new Error('Malformed OpenSSH private key');
564
+
565
+ if (cipherKey !== undefined) {
566
+ // Encrypted private key(s)
567
+ if (privBlob.length < encInfo.blockLen
568
+ || (privBlob.length % encInfo.blockLen) !== 0) {
569
+ return new Error('Malformed OpenSSH private key');
570
+ }
571
+ try {
572
+ const options = { authTagLength: encInfo.authLen };
573
+ const decipher = createDecipheriv(encInfo.sslName,
574
+ cipherKey,
575
+ cipherIV,
576
+ options);
577
+ decipher.setAutoPadding(false);
578
+ if (encInfo.authLen > 0) {
579
+ if (data.length - data._pos < encInfo.authLen)
580
+ return new Error('Malformed OpenSSH private key');
581
+ decipher.setAuthTag(
582
+ bufferSlice(data, data._pos, data._pos += encInfo.authLen)
583
+ );
584
+ }
585
+ privBlob = combineBuffers(decipher.update(privBlob),
586
+ decipher.final());
587
+ } catch (ex) {
588
+ return ex;
589
+ }
590
+ }
591
+ // Nothing should we follow the private key(s), except a possible
592
+ // authentication tag for relevant ciphers
593
+ if (data._pos !== data.length)
594
+ return new Error('Malformed OpenSSH private key');
595
+
596
+ ret = parseOpenSSHPrivKeys(privBlob, keyCount, cipherKey !== undefined);
597
+ } else {
598
+ ret = [];
599
+ }
600
+ if (ret instanceof Error)
601
+ return ret;
602
+ // This will need to change if/when OpenSSH ever starts storing multiple
603
+ // keys in their key files
604
+ return ret[0];
605
+ };
606
+
607
+ function parseOpenSSHPrivKeys(data, nkeys, decrypted) {
608
+ const keys = [];
609
+ /*
610
+ uint32 checkint
611
+ uint32 checkint
612
+ string privatekey1
613
+ string comment1
614
+ string privatekey2
615
+ string comment2
616
+ ...
617
+ string privatekeyN
618
+ string commentN
619
+ char 1
620
+ char 2
621
+ char 3
622
+ ...
623
+ char padlen % 255
624
+ */
625
+ if (data.length < 8)
626
+ return new Error('Malformed OpenSSH private key');
627
+ const check1 = readUInt32BE(data, 0);
628
+ const check2 = readUInt32BE(data, 4);
629
+ if (check1 !== check2) {
630
+ if (decrypted) {
631
+ return new Error(
632
+ 'OpenSSH key integrity check failed -- bad passphrase?'
633
+ );
634
+ }
635
+ return new Error('OpenSSH key integrity check failed');
636
+ }
637
+ data._pos = 8;
638
+ let i;
639
+ let oid;
640
+ for (i = 0; i < nkeys; ++i) {
641
+ let algo;
642
+ let privPEM;
643
+ let pubPEM;
644
+ let pubSSH;
645
+ // The OpenSSH documentation for the key format actually lies, the
646
+ // entirety of the private key content is not contained with a string
647
+ // field, it's actually the literal contents of the private key, so to be
648
+ // able to find the end of the key data you need to know the layout/format
649
+ // of each key type ...
650
+ const type = readString(data, data._pos, true);
651
+ if (type === undefined)
652
+ return new Error('Malformed OpenSSH private key');
653
+
654
+ switch (type) {
655
+ case 'ssh-rsa': {
656
+ /*
657
+ string n -- public
658
+ string e -- public
659
+ string d -- private
660
+ string iqmp -- private
661
+ string p -- private
662
+ string q -- private
663
+ */
664
+ const n = readString(data, data._pos);
665
+ if (n === undefined)
666
+ return new Error('Malformed OpenSSH private key');
667
+ const e = readString(data, data._pos);
668
+ if (e === undefined)
669
+ return new Error('Malformed OpenSSH private key');
670
+ const d = readString(data, data._pos);
671
+ if (d === undefined)
672
+ return new Error('Malformed OpenSSH private key');
673
+ const iqmp = readString(data, data._pos);
674
+ if (iqmp === undefined)
675
+ return new Error('Malformed OpenSSH private key');
676
+ const p = readString(data, data._pos);
677
+ if (p === undefined)
678
+ return new Error('Malformed OpenSSH private key');
679
+ const q = readString(data, data._pos);
680
+ if (q === undefined)
681
+ return new Error('Malformed OpenSSH private key');
682
+
683
+ pubPEM = genOpenSSLRSAPub(n, e);
684
+ pubSSH = genOpenSSHRSAPub(n, e);
685
+ privPEM = genOpenSSLRSAPriv(n, e, d, iqmp, p, q);
686
+ algo = 'sha1';
687
+ break;
688
+ }
689
+ case 'ssh-dss': {
690
+ /*
691
+ string p -- public
692
+ string q -- public
693
+ string g -- public
694
+ string y -- public
695
+ string x -- private
696
+ */
697
+ const p = readString(data, data._pos);
698
+ if (p === undefined)
699
+ return new Error('Malformed OpenSSH private key');
700
+ const q = readString(data, data._pos);
701
+ if (q === undefined)
702
+ return new Error('Malformed OpenSSH private key');
703
+ const g = readString(data, data._pos);
704
+ if (g === undefined)
705
+ return new Error('Malformed OpenSSH private key');
706
+ const y = readString(data, data._pos);
707
+ if (y === undefined)
708
+ return new Error('Malformed OpenSSH private key');
709
+ const x = readString(data, data._pos);
710
+ if (x === undefined)
711
+ return new Error('Malformed OpenSSH private key');
712
+
713
+ pubPEM = genOpenSSLDSAPub(p, q, g, y);
714
+ pubSSH = genOpenSSHDSAPub(p, q, g, y);
715
+ privPEM = genOpenSSLDSAPriv(p, q, g, y, x);
716
+ algo = 'sha1';
717
+ break;
718
+ }
719
+ case 'ssh-ed25519': {
720
+ if (!eddsaSupported)
721
+ return new Error(`Unsupported OpenSSH private key type: ${type}`);
722
+ /*
723
+ * string public key
724
+ * string private key + public key
725
+ */
726
+ const edpub = readString(data, data._pos);
727
+ if (edpub === undefined || edpub.length !== 32)
728
+ return new Error('Malformed OpenSSH private key');
729
+ const edpriv = readString(data, data._pos);
730
+ if (edpriv === undefined || edpriv.length !== 64)
731
+ return new Error('Malformed OpenSSH private key');
732
+
733
+ pubPEM = genOpenSSLEdPub(edpub);
734
+ pubSSH = genOpenSSHEdPub(edpub);
735
+ privPEM = genOpenSSLEdPriv(bufferSlice(edpriv, 0, 32));
736
+ algo = null;
737
+ break;
738
+ }
739
+ case 'ecdsa-sha2-nistp256':
740
+ algo = 'sha256';
741
+ oid = '1.2.840.10045.3.1.7';
742
+ // FALLTHROUGH
743
+ case 'ecdsa-sha2-nistp384':
744
+ if (algo === undefined) {
745
+ algo = 'sha384';
746
+ oid = '1.3.132.0.34';
747
+ }
748
+ // FALLTHROUGH
749
+ case 'ecdsa-sha2-nistp521': {
750
+ if (algo === undefined) {
751
+ algo = 'sha512';
752
+ oid = '1.3.132.0.35';
753
+ }
754
+ /*
755
+ string curve name
756
+ string Q -- public
757
+ string d -- private
758
+ */
759
+ // TODO: validate curve name against type
760
+ if (!skipFields(data, 1)) // Skip curve name
761
+ return new Error('Malformed OpenSSH private key');
762
+ const ecpub = readString(data, data._pos);
763
+ if (ecpub === undefined)
764
+ return new Error('Malformed OpenSSH private key');
765
+ const ecpriv = readString(data, data._pos);
766
+ if (ecpriv === undefined)
767
+ return new Error('Malformed OpenSSH private key');
768
+
769
+ pubPEM = genOpenSSLECDSAPub(oid, ecpub);
770
+ pubSSH = genOpenSSHECDSAPub(oid, ecpub);
771
+ privPEM = genOpenSSLECDSAPriv(oid, ecpub, ecpriv);
772
+ break;
773
+ }
774
+ default:
775
+ return new Error(`Unsupported OpenSSH private key type: ${type}`);
776
+ }
777
+
778
+ const privComment = readString(data, data._pos, true);
779
+ if (privComment === undefined)
780
+ return new Error('Malformed OpenSSH private key');
781
+
782
+ keys.push(
783
+ new OpenSSH_Private(type, privComment, privPEM, pubPEM, pubSSH, algo,
784
+ decrypted)
785
+ );
786
+ }
787
+ let cnt = 0;
788
+ for (i = data._pos; i < data.length; ++i) {
789
+ if (data[i] !== (++cnt % 255))
790
+ return new Error('Malformed OpenSSH private key');
791
+ }
792
+
793
+ return keys;
794
+ }
795
+ }
796
+
797
+
798
+ function OpenSSH_Old_Private(type, comment, privPEM, pubPEM, pubSSH, algo,
799
+ decrypted) {
800
+ this.type = type;
801
+ this.comment = comment;
802
+ this[SYM_PRIV_PEM] = privPEM;
803
+ this[SYM_PUB_PEM] = pubPEM;
804
+ this[SYM_PUB_SSH] = pubSSH;
805
+ this[SYM_HASH_ALGO] = algo;
806
+ this[SYM_DECRYPTED] = decrypted;
807
+ }
808
+ OpenSSH_Old_Private.prototype = BaseKey;
809
+ {
810
+ const regexp = /^-----BEGIN (RSA|DSA|EC) PRIVATE KEY-----(?:\r\n|\n)((?:[^:]+:\s*[\S].*(?:\r\n|\n))*)([\s\S]+)(?:\r\n|\n)-----END (RSA|DSA|EC) PRIVATE KEY-----$/;
811
+ OpenSSH_Old_Private.parse = (str, passphrase) => {
812
+ const m = regexp.exec(str);
813
+ if (m === null)
814
+ return null;
815
+ let privBlob = Buffer.from(m[3], 'base64');
816
+ let headers = m[2];
817
+ let decrypted = false;
818
+ if (headers !== undefined) {
819
+ // encrypted key
820
+ headers = headers.split(/\r\n|\n/g);
821
+ for (let i = 0; i < headers.length; ++i) {
822
+ const header = headers[i];
823
+ let sepIdx = header.indexOf(':');
824
+ if (header.slice(0, sepIdx) === 'DEK-Info') {
825
+ const val = header.slice(sepIdx + 2);
826
+ sepIdx = val.indexOf(',');
827
+ if (sepIdx === -1)
828
+ continue;
829
+ const cipherName = val.slice(0, sepIdx).toLowerCase();
830
+ if (supportedOpenSSLCiphers.indexOf(cipherName) === -1) {
831
+ return new Error(
832
+ `Cipher (${cipherName}) not supported `
833
+ + 'for encrypted OpenSSH private key'
834
+ );
835
+ }
836
+ const encInfo = CIPHER_INFO_OPENSSL[cipherName];
837
+ if (!encInfo) {
838
+ return new Error(
839
+ `Cipher (${cipherName}) not supported `
840
+ + 'for encrypted OpenSSH private key'
841
+ );
842
+ }
843
+ const cipherIV = Buffer.from(val.slice(sepIdx + 1), 'hex');
844
+ if (cipherIV.length !== encInfo.ivLen)
845
+ return new Error('Malformed encrypted OpenSSH private key');
846
+ if (!passphrase) {
847
+ return new Error(
848
+ 'Encrypted OpenSSH private key detected, but no passphrase given'
849
+ );
850
+ }
851
+ const ivSlice = bufferSlice(cipherIV, 0, 8);
852
+ let cipherKey = createHash('md5')
853
+ .update(passphrase)
854
+ .update(ivSlice)
855
+ .digest();
856
+ while (cipherKey.length < encInfo.keyLen) {
857
+ cipherKey = combineBuffers(
858
+ cipherKey,
859
+ createHash('md5')
860
+ .update(cipherKey)
861
+ .update(passphrase)
862
+ .update(ivSlice)
863
+ .digest()
864
+ );
865
+ }
866
+ if (cipherKey.length > encInfo.keyLen)
867
+ cipherKey = bufferSlice(cipherKey, 0, encInfo.keyLen);
868
+ try {
869
+ const decipher = createDecipheriv(cipherName, cipherKey, cipherIV);
870
+ decipher.setAutoPadding(false);
871
+ privBlob = combineBuffers(decipher.update(privBlob),
872
+ decipher.final());
873
+ decrypted = true;
874
+ } catch (ex) {
875
+ return ex;
876
+ }
877
+ }
878
+ }
879
+ }
880
+
881
+ let type;
882
+ let privPEM;
883
+ let pubPEM;
884
+ let pubSSH;
885
+ let algo;
886
+ let reader;
887
+ let errMsg = 'Malformed OpenSSH private key';
888
+ if (decrypted)
889
+ errMsg += '. Bad passphrase?';
890
+ switch (m[1]) {
891
+ case 'RSA':
892
+ type = 'ssh-rsa';
893
+ privPEM = makePEM('RSA PRIVATE', privBlob);
894
+ try {
895
+ reader = new Ber.Reader(privBlob);
896
+ reader.readSequence();
897
+ reader.readInt(); // skip version
898
+ const n = reader.readString(Ber.Integer, true);
899
+ if (n === null)
900
+ return new Error(errMsg);
901
+ const e = reader.readString(Ber.Integer, true);
902
+ if (e === null)
903
+ return new Error(errMsg);
904
+ pubPEM = genOpenSSLRSAPub(n, e);
905
+ pubSSH = genOpenSSHRSAPub(n, e);
906
+ } catch {
907
+ return new Error(errMsg);
908
+ }
909
+ algo = 'sha1';
910
+ break;
911
+ case 'DSA':
912
+ type = 'ssh-dss';
913
+ privPEM = makePEM('DSA PRIVATE', privBlob);
914
+ try {
915
+ reader = new Ber.Reader(privBlob);
916
+ reader.readSequence();
917
+ reader.readInt(); // skip version
918
+ const p = reader.readString(Ber.Integer, true);
919
+ if (p === null)
920
+ return new Error(errMsg);
921
+ const q = reader.readString(Ber.Integer, true);
922
+ if (q === null)
923
+ return new Error(errMsg);
924
+ const g = reader.readString(Ber.Integer, true);
925
+ if (g === null)
926
+ return new Error(errMsg);
927
+ const y = reader.readString(Ber.Integer, true);
928
+ if (y === null)
929
+ return new Error(errMsg);
930
+ pubPEM = genOpenSSLDSAPub(p, q, g, y);
931
+ pubSSH = genOpenSSHDSAPub(p, q, g, y);
932
+ } catch {
933
+ return new Error(errMsg);
934
+ }
935
+ algo = 'sha1';
936
+ break;
937
+ case 'EC': {
938
+ let ecSSLName;
939
+ let ecPriv;
940
+ let ecOID;
941
+ try {
942
+ reader = new Ber.Reader(privBlob);
943
+ reader.readSequence();
944
+ reader.readInt(); // skip version
945
+ ecPriv = reader.readString(Ber.OctetString, true);
946
+ reader.readByte(); // Skip "complex" context type byte
947
+ const offset = reader.readLength(); // Skip context length
948
+ if (offset !== null) {
949
+ reader._offset = offset;
950
+ ecOID = reader.readOID();
951
+ if (ecOID === null)
952
+ return new Error(errMsg);
953
+ switch (ecOID) {
954
+ case '1.2.840.10045.3.1.7':
955
+ // prime256v1/secp256r1
956
+ ecSSLName = 'prime256v1';
957
+ type = 'ecdsa-sha2-nistp256';
958
+ algo = 'sha256';
959
+ break;
960
+ case '1.3.132.0.34':
961
+ // secp384r1
962
+ ecSSLName = 'secp384r1';
963
+ type = 'ecdsa-sha2-nistp384';
964
+ algo = 'sha384';
965
+ break;
966
+ case '1.3.132.0.35':
967
+ // secp521r1
968
+ ecSSLName = 'secp521r1';
969
+ type = 'ecdsa-sha2-nistp521';
970
+ algo = 'sha512';
971
+ break;
972
+ default:
973
+ return new Error(`Unsupported private key EC OID: ${ecOID}`);
974
+ }
975
+ } else {
976
+ return new Error(errMsg);
977
+ }
978
+ } catch {
979
+ return new Error(errMsg);
980
+ }
981
+ privPEM = makePEM('EC PRIVATE', privBlob);
982
+ const pubBlob = genOpenSSLECDSAPubFromPriv(ecSSLName, ecPriv);
983
+ pubPEM = genOpenSSLECDSAPub(ecOID, pubBlob);
984
+ pubSSH = genOpenSSHECDSAPub(ecOID, pubBlob);
985
+ break;
986
+ }
987
+ }
988
+
989
+ return new OpenSSH_Old_Private(type, '', privPEM, pubPEM, pubSSH, algo,
990
+ decrypted);
991
+ };
992
+ }
993
+
994
+
995
+ function PPK_Private(type, comment, privPEM, pubPEM, pubSSH, algo, decrypted) {
996
+ this.type = type;
997
+ this.comment = comment;
998
+ this[SYM_PRIV_PEM] = privPEM;
999
+ this[SYM_PUB_PEM] = pubPEM;
1000
+ this[SYM_PUB_SSH] = pubSSH;
1001
+ this[SYM_HASH_ALGO] = algo;
1002
+ this[SYM_DECRYPTED] = decrypted;
1003
+ }
1004
+ PPK_Private.prototype = BaseKey;
1005
+ {
1006
+ const EMPTY_PASSPHRASE = Buffer.alloc(0);
1007
+ const PPK_IV = Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
1008
+ const PPK_PP1 = Buffer.from([0, 0, 0, 0]);
1009
+ const PPK_PP2 = Buffer.from([0, 0, 0, 1]);
1010
+ const regexp = /^PuTTY-User-Key-File-2: (ssh-(?:rsa|dss))\r?\nEncryption: (aes256-cbc|none)\r?\nComment: ([^\r\n]*)\r?\nPublic-Lines: \d+\r?\n([\s\S]+?)\r?\nPrivate-Lines: \d+\r?\n([\s\S]+?)\r?\nPrivate-MAC: ([^\r\n]+)/;
1011
+ PPK_Private.parse = (str, passphrase) => {
1012
+ const m = regexp.exec(str);
1013
+ if (m === null)
1014
+ return null;
1015
+ // m[1] = key type
1016
+ // m[2] = encryption type
1017
+ // m[3] = comment
1018
+ // m[4] = base64-encoded public key data:
1019
+ // for "ssh-rsa":
1020
+ // string "ssh-rsa"
1021
+ // mpint e (public exponent)
1022
+ // mpint n (modulus)
1023
+ // for "ssh-dss":
1024
+ // string "ssh-dss"
1025
+ // mpint p (modulus)
1026
+ // mpint q (prime)
1027
+ // mpint g (base number)
1028
+ // mpint y (public key parameter: g^x mod p)
1029
+ // m[5] = base64-encoded private key data:
1030
+ // for "ssh-rsa":
1031
+ // mpint d (private exponent)
1032
+ // mpint p (prime 1)
1033
+ // mpint q (prime 2)
1034
+ // mpint iqmp ([inverse of q] mod p)
1035
+ // for "ssh-dss":
1036
+ // mpint x (private key parameter)
1037
+ // m[6] = SHA1 HMAC over:
1038
+ // string name of algorithm ("ssh-dss", "ssh-rsa")
1039
+ // string encryption type
1040
+ // string comment
1041
+ // string public key data
1042
+ // string private-plaintext (including the final padding)
1043
+ const cipherName = m[2];
1044
+ const encrypted = (cipherName !== 'none');
1045
+ if (encrypted && !passphrase) {
1046
+ return new Error(
1047
+ 'Encrypted PPK private key detected, but no passphrase given'
1048
+ );
1049
+ }
1050
+
1051
+ let privBlob = Buffer.from(m[5], 'base64');
1052
+
1053
+ if (encrypted) {
1054
+ const encInfo = CIPHER_INFO[cipherName];
1055
+ let cipherKey = combineBuffers(
1056
+ createHash('sha1').update(PPK_PP1).update(passphrase).digest(),
1057
+ createHash('sha1').update(PPK_PP2).update(passphrase).digest()
1058
+ );
1059
+ if (cipherKey.length > encInfo.keyLen)
1060
+ cipherKey = bufferSlice(cipherKey, 0, encInfo.keyLen);
1061
+ try {
1062
+ const decipher = createDecipheriv(encInfo.sslName, cipherKey, PPK_IV);
1063
+ decipher.setAutoPadding(false);
1064
+ privBlob = combineBuffers(decipher.update(privBlob),
1065
+ decipher.final());
1066
+ } catch (ex) {
1067
+ return ex;
1068
+ }
1069
+ }
1070
+
1071
+ const type = m[1];
1072
+ const comment = m[3];
1073
+ const pubBlob = Buffer.from(m[4], 'base64');
1074
+
1075
+ const mac = m[6];
1076
+ const typeLen = type.length;
1077
+ const cipherNameLen = cipherName.length;
1078
+ const commentLen = Buffer.byteLength(comment);
1079
+ const pubLen = pubBlob.length;
1080
+ const privLen = privBlob.length;
1081
+ const macData = Buffer.allocUnsafe(4 + typeLen
1082
+ + 4 + cipherNameLen
1083
+ + 4 + commentLen
1084
+ + 4 + pubLen
1085
+ + 4 + privLen);
1086
+ let p = 0;
1087
+
1088
+ writeUInt32BE(macData, typeLen, p);
1089
+ macData.utf8Write(type, p += 4, typeLen);
1090
+ writeUInt32BE(macData, cipherNameLen, p += typeLen);
1091
+ macData.utf8Write(cipherName, p += 4, cipherNameLen);
1092
+ writeUInt32BE(macData, commentLen, p += cipherNameLen);
1093
+ macData.utf8Write(comment, p += 4, commentLen);
1094
+ writeUInt32BE(macData, pubLen, p += commentLen);
1095
+ macData.set(pubBlob, p += 4);
1096
+ writeUInt32BE(macData, privLen, p += pubLen);
1097
+ macData.set(privBlob, p + 4);
1098
+
1099
+ if (!passphrase)
1100
+ passphrase = EMPTY_PASSPHRASE;
1101
+
1102
+ const calcMAC = createHmac(
1103
+ 'sha1',
1104
+ createHash('sha1')
1105
+ .update('putty-private-key-file-mac-key')
1106
+ .update(passphrase)
1107
+ .digest()
1108
+ ).update(macData).digest('hex');
1109
+
1110
+ if (calcMAC !== mac) {
1111
+ if (encrypted) {
1112
+ return new Error(
1113
+ 'PPK private key integrity check failed -- bad passphrase?'
1114
+ );
1115
+ }
1116
+ return new Error('PPK private key integrity check failed');
1117
+ }
1118
+
1119
+ let pubPEM;
1120
+ let pubSSH;
1121
+ let privPEM;
1122
+ pubBlob._pos = 0;
1123
+ skipFields(pubBlob, 1); // skip (duplicate) key type
1124
+ switch (type) {
1125
+ case 'ssh-rsa': {
1126
+ const e = readString(pubBlob, pubBlob._pos);
1127
+ if (e === undefined)
1128
+ return new Error('Malformed PPK public key');
1129
+ const n = readString(pubBlob, pubBlob._pos);
1130
+ if (n === undefined)
1131
+ return new Error('Malformed PPK public key');
1132
+ const d = readString(privBlob, 0);
1133
+ if (d === undefined)
1134
+ return new Error('Malformed PPK private key');
1135
+ const p = readString(privBlob, privBlob._pos);
1136
+ if (p === undefined)
1137
+ return new Error('Malformed PPK private key');
1138
+ const q = readString(privBlob, privBlob._pos);
1139
+ if (q === undefined)
1140
+ return new Error('Malformed PPK private key');
1141
+ const iqmp = readString(privBlob, privBlob._pos);
1142
+ if (iqmp === undefined)
1143
+ return new Error('Malformed PPK private key');
1144
+ pubPEM = genOpenSSLRSAPub(n, e);
1145
+ pubSSH = genOpenSSHRSAPub(n, e);
1146
+ privPEM = genOpenSSLRSAPriv(n, e, d, iqmp, p, q);
1147
+ break;
1148
+ }
1149
+ case 'ssh-dss': {
1150
+ const p = readString(pubBlob, pubBlob._pos);
1151
+ if (p === undefined)
1152
+ return new Error('Malformed PPK public key');
1153
+ const q = readString(pubBlob, pubBlob._pos);
1154
+ if (q === undefined)
1155
+ return new Error('Malformed PPK public key');
1156
+ const g = readString(pubBlob, pubBlob._pos);
1157
+ if (g === undefined)
1158
+ return new Error('Malformed PPK public key');
1159
+ const y = readString(pubBlob, pubBlob._pos);
1160
+ if (y === undefined)
1161
+ return new Error('Malformed PPK public key');
1162
+ const x = readString(privBlob, 0);
1163
+ if (x === undefined)
1164
+ return new Error('Malformed PPK private key');
1165
+
1166
+ pubPEM = genOpenSSLDSAPub(p, q, g, y);
1167
+ pubSSH = genOpenSSHDSAPub(p, q, g, y);
1168
+ privPEM = genOpenSSLDSAPriv(p, q, g, y, x);
1169
+ break;
1170
+ }
1171
+ }
1172
+
1173
+ return new PPK_Private(type, comment, privPEM, pubPEM, pubSSH, 'sha1',
1174
+ encrypted);
1175
+ };
1176
+ }
1177
+
1178
+
1179
+ function OpenSSH_Public(type, comment, pubPEM, pubSSH, algo) {
1180
+ this.type = type;
1181
+ this.comment = comment;
1182
+ this[SYM_PRIV_PEM] = null;
1183
+ this[SYM_PUB_PEM] = pubPEM;
1184
+ this[SYM_PUB_SSH] = pubSSH;
1185
+ this[SYM_HASH_ALGO] = algo;
1186
+ this[SYM_DECRYPTED] = false;
1187
+ }
1188
+ OpenSSH_Public.prototype = BaseKey;
1189
+ {
1190
+ let regexp;
1191
+ if (eddsaSupported)
1192
+ regexp = /^(((?:ssh-(?:rsa|dss|ed25519))|ecdsa-sha2-nistp(?:256|384|521))(?:-cert-v0[01]@openssh.com)?) ([A-Z0-9a-z/+=]+)(?:$|\s+([\S].*)?)$/;
1193
+ else
1194
+ regexp = /^(((?:ssh-(?:rsa|dss))|ecdsa-sha2-nistp(?:256|384|521))(?:-cert-v0[01]@openssh.com)?) ([A-Z0-9a-z/+=]+)(?:$|\s+([\S].*)?)$/;
1195
+ OpenSSH_Public.parse = (str) => {
1196
+ const m = regexp.exec(str);
1197
+ if (m === null)
1198
+ return null;
1199
+ // m[1] = full type
1200
+ // m[2] = base type
1201
+ // m[3] = base64-encoded public key
1202
+ // m[4] = comment
1203
+
1204
+ const fullType = m[1];
1205
+ const baseType = m[2];
1206
+ const data = Buffer.from(m[3], 'base64');
1207
+ const comment = (m[4] || '');
1208
+
1209
+ const type = readString(data, data._pos, true);
1210
+ if (type === undefined || type.indexOf(baseType) !== 0)
1211
+ return new Error('Malformed OpenSSH public key');
1212
+
1213
+ return parseDER(data, baseType, comment, fullType);
1214
+ };
1215
+ }
1216
+
1217
+
1218
+ function RFC4716_Public(type, comment, pubPEM, pubSSH, algo) {
1219
+ this.type = type;
1220
+ this.comment = comment;
1221
+ this[SYM_PRIV_PEM] = null;
1222
+ this[SYM_PUB_PEM] = pubPEM;
1223
+ this[SYM_PUB_SSH] = pubSSH;
1224
+ this[SYM_HASH_ALGO] = algo;
1225
+ this[SYM_DECRYPTED] = false;
1226
+ }
1227
+ RFC4716_Public.prototype = BaseKey;
1228
+ {
1229
+ const regexp = /^---- BEGIN SSH2 PUBLIC KEY ----(?:\r?\n)((?:.{0,72}\r?\n)+)---- END SSH2 PUBLIC KEY ----$/;
1230
+ const RE_DATA = /^[A-Z0-9a-z/+=\r\n]+$/;
1231
+ const RE_HEADER = /^([\x21-\x39\x3B-\x7E]{1,64}): ((?:[^\\]*\\\r?\n)*[^\r\n]+)\r?\n/gm;
1232
+ const RE_HEADER_ENDS = /\\\r?\n/g;
1233
+ RFC4716_Public.parse = (str) => {
1234
+ let m = regexp.exec(str);
1235
+ if (m === null)
1236
+ return null;
1237
+
1238
+ const body = m[1];
1239
+ let dataStart = 0;
1240
+ let comment = '';
1241
+
1242
+ while (m = RE_HEADER.exec(body)) {
1243
+ const headerName = m[1];
1244
+ const headerValue = m[2].replace(RE_HEADER_ENDS, '');
1245
+ if (headerValue.length > 1024) {
1246
+ RE_HEADER.lastIndex = 0;
1247
+ return new Error('Malformed RFC4716 public key');
1248
+ }
1249
+
1250
+ dataStart = RE_HEADER.lastIndex;
1251
+
1252
+ if (headerName.toLowerCase() === 'comment') {
1253
+ comment = headerValue;
1254
+ if (comment.length > 1
1255
+ && comment.charCodeAt(0) === 34/* '"' */
1256
+ && comment.charCodeAt(comment.length - 1) === 34/* '"' */) {
1257
+ comment = comment.slice(1, -1);
1258
+ }
1259
+ }
1260
+ }
1261
+
1262
+ let data = body.slice(dataStart);
1263
+ if (!RE_DATA.test(data))
1264
+ return new Error('Malformed RFC4716 public key');
1265
+
1266
+ data = Buffer.from(data, 'base64');
1267
+
1268
+ const type = readString(data, 0, true);
1269
+ if (type === undefined)
1270
+ return new Error('Malformed RFC4716 public key');
1271
+
1272
+ let pubPEM = null;
1273
+ let pubSSH = null;
1274
+ switch (type) {
1275
+ case 'ssh-rsa': {
1276
+ const e = readString(data, data._pos);
1277
+ if (e === undefined)
1278
+ return new Error('Malformed RFC4716 public key');
1279
+ const n = readString(data, data._pos);
1280
+ if (n === undefined)
1281
+ return new Error('Malformed RFC4716 public key');
1282
+ pubPEM = genOpenSSLRSAPub(n, e);
1283
+ pubSSH = genOpenSSHRSAPub(n, e);
1284
+ break;
1285
+ }
1286
+ case 'ssh-dss': {
1287
+ const p = readString(data, data._pos);
1288
+ if (p === undefined)
1289
+ return new Error('Malformed RFC4716 public key');
1290
+ const q = readString(data, data._pos);
1291
+ if (q === undefined)
1292
+ return new Error('Malformed RFC4716 public key');
1293
+ const g = readString(data, data._pos);
1294
+ if (g === undefined)
1295
+ return new Error('Malformed RFC4716 public key');
1296
+ const y = readString(data, data._pos);
1297
+ if (y === undefined)
1298
+ return new Error('Malformed RFC4716 public key');
1299
+ pubPEM = genOpenSSLDSAPub(p, q, g, y);
1300
+ pubSSH = genOpenSSHDSAPub(p, q, g, y);
1301
+ break;
1302
+ }
1303
+ default:
1304
+ return new Error('Malformed RFC4716 public key');
1305
+ }
1306
+
1307
+ return new RFC4716_Public(type, comment, pubPEM, pubSSH, 'sha1');
1308
+ };
1309
+ }
1310
+
1311
+
1312
+ function parseDER(data, baseType, comment, fullType) {
1313
+ if (!isSupportedKeyType(baseType))
1314
+ return new Error(`Unsupported OpenSSH public key type: ${baseType}`);
1315
+
1316
+ let algo;
1317
+ let oid;
1318
+ let pubPEM = null;
1319
+ let pubSSH = null;
1320
+
1321
+ switch (baseType) {
1322
+ case 'ssh-rsa': {
1323
+ const e = readString(data, data._pos || 0);
1324
+ if (e === undefined)
1325
+ return new Error('Malformed OpenSSH public key');
1326
+ const n = readString(data, data._pos);
1327
+ if (n === undefined)
1328
+ return new Error('Malformed OpenSSH public key');
1329
+ pubPEM = genOpenSSLRSAPub(n, e);
1330
+ pubSSH = genOpenSSHRSAPub(n, e);
1331
+ algo = 'sha1';
1332
+ break;
1333
+ }
1334
+ case 'ssh-dss': {
1335
+ const p = readString(data, data._pos || 0);
1336
+ if (p === undefined)
1337
+ return new Error('Malformed OpenSSH public key');
1338
+ const q = readString(data, data._pos);
1339
+ if (q === undefined)
1340
+ return new Error('Malformed OpenSSH public key');
1341
+ const g = readString(data, data._pos);
1342
+ if (g === undefined)
1343
+ return new Error('Malformed OpenSSH public key');
1344
+ const y = readString(data, data._pos);
1345
+ if (y === undefined)
1346
+ return new Error('Malformed OpenSSH public key');
1347
+ pubPEM = genOpenSSLDSAPub(p, q, g, y);
1348
+ pubSSH = genOpenSSHDSAPub(p, q, g, y);
1349
+ algo = 'sha1';
1350
+ break;
1351
+ }
1352
+ case 'ssh-ed25519': {
1353
+ const edpub = readString(data, data._pos || 0);
1354
+ if (edpub === undefined || edpub.length !== 32)
1355
+ return new Error('Malformed OpenSSH public key');
1356
+ pubPEM = genOpenSSLEdPub(edpub);
1357
+ pubSSH = genOpenSSHEdPub(edpub);
1358
+ algo = null;
1359
+ break;
1360
+ }
1361
+ case 'ecdsa-sha2-nistp256':
1362
+ algo = 'sha256';
1363
+ oid = '1.2.840.10045.3.1.7';
1364
+ // FALLTHROUGH
1365
+ case 'ecdsa-sha2-nistp384':
1366
+ if (algo === undefined) {
1367
+ algo = 'sha384';
1368
+ oid = '1.3.132.0.34';
1369
+ }
1370
+ // FALLTHROUGH
1371
+ case 'ecdsa-sha2-nistp521': {
1372
+ if (algo === undefined) {
1373
+ algo = 'sha512';
1374
+ oid = '1.3.132.0.35';
1375
+ }
1376
+ // TODO: validate curve name against type
1377
+ if (!skipFields(data, 1)) // Skip curve name
1378
+ return new Error('Malformed OpenSSH public key');
1379
+ const ecpub = readString(data, data._pos || 0);
1380
+ if (ecpub === undefined)
1381
+ return new Error('Malformed OpenSSH public key');
1382
+ pubPEM = genOpenSSLECDSAPub(oid, ecpub);
1383
+ pubSSH = genOpenSSHECDSAPub(oid, ecpub);
1384
+ break;
1385
+ }
1386
+ default:
1387
+ return new Error(`Unsupported OpenSSH public key type: ${baseType}`);
1388
+ }
1389
+
1390
+ return new OpenSSH_Public(fullType, comment, pubPEM, pubSSH, algo);
1391
+ }
1392
+
1393
+ function isSupportedKeyType(type) {
1394
+ switch (type) {
1395
+ case 'ssh-rsa':
1396
+ case 'ssh-dss':
1397
+ case 'ecdsa-sha2-nistp256':
1398
+ case 'ecdsa-sha2-nistp384':
1399
+ case 'ecdsa-sha2-nistp521':
1400
+ return true;
1401
+ case 'ssh-ed25519':
1402
+ if (eddsaSupported)
1403
+ return true;
1404
+ // FALLTHROUGH
1405
+ default:
1406
+ return false;
1407
+ }
1408
+ }
1409
+
1410
+ function isParsedKey(val) {
1411
+ if (!val)
1412
+ return false;
1413
+ return (typeof val[SYM_DECRYPTED] === 'boolean');
1414
+ }
1415
+
1416
+ function parseKey(data, passphrase) {
1417
+ if (isParsedKey(data))
1418
+ return data;
1419
+
1420
+ let origBuffer;
1421
+ if (Buffer.isBuffer(data)) {
1422
+ origBuffer = data;
1423
+ data = data.utf8Slice(0, data.length).trim();
1424
+ } else if (typeof data === 'string') {
1425
+ data = data.trim();
1426
+ } else {
1427
+ return new Error('Key data must be a Buffer or string');
1428
+ }
1429
+
1430
+ // eslint-disable-next-line eqeqeq
1431
+ if (passphrase != undefined) {
1432
+ if (typeof passphrase === 'string')
1433
+ passphrase = Buffer.from(passphrase);
1434
+ else if (!Buffer.isBuffer(passphrase))
1435
+ return new Error('Passphrase must be a string or Buffer when supplied');
1436
+ }
1437
+
1438
+ let ret;
1439
+
1440
+ // First try as printable string format (e.g. PEM)
1441
+
1442
+ // Private keys
1443
+ if ((ret = OpenSSH_Private.parse(data, passphrase)) !== null)
1444
+ return ret;
1445
+ if ((ret = OpenSSH_Old_Private.parse(data, passphrase)) !== null)
1446
+ return ret;
1447
+ if ((ret = PPK_Private.parse(data, passphrase)) !== null)
1448
+ return ret;
1449
+
1450
+ // Public keys
1451
+ if ((ret = OpenSSH_Public.parse(data)) !== null)
1452
+ return ret;
1453
+ if ((ret = RFC4716_Public.parse(data)) !== null)
1454
+ return ret;
1455
+
1456
+ // Finally try as a binary format if we were originally passed binary data
1457
+ if (origBuffer) {
1458
+ binaryKeyParser.init(origBuffer, 0);
1459
+ const type = binaryKeyParser.readString(true);
1460
+ if (type !== undefined) {
1461
+ data = binaryKeyParser.readRaw();
1462
+ if (data !== undefined) {
1463
+ ret = parseDER(data, type, '', type);
1464
+ // Ignore potentially useless errors in case the data was not actually
1465
+ // in the binary format
1466
+ if (ret instanceof Error)
1467
+ ret = null;
1468
+ }
1469
+ }
1470
+ binaryKeyParser.clear();
1471
+ }
1472
+
1473
+ if (ret)
1474
+ return ret;
1475
+
1476
+ return new Error('Unsupported key format');
1477
+ }
1478
+
1479
+ module.exports = {
1480
+ isParsedKey,
1481
+ isSupportedKeyType,
1482
+ parseDERKey: (data, type) => parseDER(data, type, '', type),
1483
+ parseKey,
1484
+ };