source: trip-planner-front/node_modules/sshpk/lib/key.js@ b738035

Last change on this file since b738035 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 7.9 KB
RevLine 
[6a3a178]1// Copyright 2018 Joyent, Inc.
2
3module.exports = Key;
4
5var assert = require('assert-plus');
6var algs = require('./algs');
7var crypto = require('crypto');
8var Fingerprint = require('./fingerprint');
9var Signature = require('./signature');
10var DiffieHellman = require('./dhe').DiffieHellman;
11var errs = require('./errors');
12var utils = require('./utils');
13var PrivateKey = require('./private-key');
14var edCompat;
15
16try {
17 edCompat = require('./ed-compat');
18} catch (e) {
19 /* Just continue through, and bail out if we try to use it. */
20}
21
22var InvalidAlgorithmError = errs.InvalidAlgorithmError;
23var KeyParseError = errs.KeyParseError;
24
25var formats = {};
26formats['auto'] = require('./formats/auto');
27formats['pem'] = require('./formats/pem');
28formats['pkcs1'] = require('./formats/pkcs1');
29formats['pkcs8'] = require('./formats/pkcs8');
30formats['rfc4253'] = require('./formats/rfc4253');
31formats['ssh'] = require('./formats/ssh');
32formats['ssh-private'] = require('./formats/ssh-private');
33formats['openssh'] = formats['ssh-private'];
34formats['dnssec'] = require('./formats/dnssec');
35formats['putty'] = require('./formats/putty');
36formats['ppk'] = formats['putty'];
37
38function Key(opts) {
39 assert.object(opts, 'options');
40 assert.arrayOfObject(opts.parts, 'options.parts');
41 assert.string(opts.type, 'options.type');
42 assert.optionalString(opts.comment, 'options.comment');
43
44 var algInfo = algs.info[opts.type];
45 if (typeof (algInfo) !== 'object')
46 throw (new InvalidAlgorithmError(opts.type));
47
48 var partLookup = {};
49 for (var i = 0; i < opts.parts.length; ++i) {
50 var part = opts.parts[i];
51 partLookup[part.name] = part;
52 }
53
54 this.type = opts.type;
55 this.parts = opts.parts;
56 this.part = partLookup;
57 this.comment = undefined;
58 this.source = opts.source;
59
60 /* for speeding up hashing/fingerprint operations */
61 this._rfc4253Cache = opts._rfc4253Cache;
62 this._hashCache = {};
63
64 var sz;
65 this.curve = undefined;
66 if (this.type === 'ecdsa') {
67 var curve = this.part.curve.data.toString();
68 this.curve = curve;
69 sz = algs.curves[curve].size;
70 } else if (this.type === 'ed25519' || this.type === 'curve25519') {
71 sz = 256;
72 this.curve = 'curve25519';
73 } else {
74 var szPart = this.part[algInfo.sizePart];
75 sz = szPart.data.length;
76 sz = sz * 8 - utils.countZeros(szPart.data);
77 }
78 this.size = sz;
79}
80
81Key.formats = formats;
82
83Key.prototype.toBuffer = function (format, options) {
84 if (format === undefined)
85 format = 'ssh';
86 assert.string(format, 'format');
87 assert.object(formats[format], 'formats[format]');
88 assert.optionalObject(options, 'options');
89
90 if (format === 'rfc4253') {
91 if (this._rfc4253Cache === undefined)
92 this._rfc4253Cache = formats['rfc4253'].write(this);
93 return (this._rfc4253Cache);
94 }
95
96 return (formats[format].write(this, options));
97};
98
99Key.prototype.toString = function (format, options) {
100 return (this.toBuffer(format, options).toString());
101};
102
103Key.prototype.hash = function (algo, type) {
104 assert.string(algo, 'algorithm');
105 assert.optionalString(type, 'type');
106 if (type === undefined)
107 type = 'ssh';
108 algo = algo.toLowerCase();
109 if (algs.hashAlgs[algo] === undefined)
110 throw (new InvalidAlgorithmError(algo));
111
112 var cacheKey = algo + '||' + type;
113 if (this._hashCache[cacheKey])
114 return (this._hashCache[cacheKey]);
115
116 var buf;
117 if (type === 'ssh') {
118 buf = this.toBuffer('rfc4253');
119 } else if (type === 'spki') {
120 buf = formats.pkcs8.pkcs8ToBuffer(this);
121 } else {
122 throw (new Error('Hash type ' + type + ' not supported'));
123 }
124 var hash = crypto.createHash(algo).update(buf).digest();
125 this._hashCache[cacheKey] = hash;
126 return (hash);
127};
128
129Key.prototype.fingerprint = function (algo, type) {
130 if (algo === undefined)
131 algo = 'sha256';
132 if (type === undefined)
133 type = 'ssh';
134 assert.string(algo, 'algorithm');
135 assert.string(type, 'type');
136 var opts = {
137 type: 'key',
138 hash: this.hash(algo, type),
139 algorithm: algo,
140 hashType: type
141 };
142 return (new Fingerprint(opts));
143};
144
145Key.prototype.defaultHashAlgorithm = function () {
146 var hashAlgo = 'sha1';
147 if (this.type === 'rsa')
148 hashAlgo = 'sha256';
149 if (this.type === 'dsa' && this.size > 1024)
150 hashAlgo = 'sha256';
151 if (this.type === 'ed25519')
152 hashAlgo = 'sha512';
153 if (this.type === 'ecdsa') {
154 if (this.size <= 256)
155 hashAlgo = 'sha256';
156 else if (this.size <= 384)
157 hashAlgo = 'sha384';
158 else
159 hashAlgo = 'sha512';
160 }
161 return (hashAlgo);
162};
163
164Key.prototype.createVerify = function (hashAlgo) {
165 if (hashAlgo === undefined)
166 hashAlgo = this.defaultHashAlgorithm();
167 assert.string(hashAlgo, 'hash algorithm');
168
169 /* ED25519 is not supported by OpenSSL, use a javascript impl. */
170 if (this.type === 'ed25519' && edCompat !== undefined)
171 return (new edCompat.Verifier(this, hashAlgo));
172 if (this.type === 'curve25519')
173 throw (new Error('Curve25519 keys are not suitable for ' +
174 'signing or verification'));
175
176 var v, nm, err;
177 try {
178 nm = hashAlgo.toUpperCase();
179 v = crypto.createVerify(nm);
180 } catch (e) {
181 err = e;
182 }
183 if (v === undefined || (err instanceof Error &&
184 err.message.match(/Unknown message digest/))) {
185 nm = 'RSA-';
186 nm += hashAlgo.toUpperCase();
187 v = crypto.createVerify(nm);
188 }
189 assert.ok(v, 'failed to create verifier');
190 var oldVerify = v.verify.bind(v);
191 var key = this.toBuffer('pkcs8');
192 var curve = this.curve;
193 var self = this;
194 v.verify = function (signature, fmt) {
195 if (Signature.isSignature(signature, [2, 0])) {
196 if (signature.type !== self.type)
197 return (false);
198 if (signature.hashAlgorithm &&
199 signature.hashAlgorithm !== hashAlgo)
200 return (false);
201 if (signature.curve && self.type === 'ecdsa' &&
202 signature.curve !== curve)
203 return (false);
204 return (oldVerify(key, signature.toBuffer('asn1')));
205
206 } else if (typeof (signature) === 'string' ||
207 Buffer.isBuffer(signature)) {
208 return (oldVerify(key, signature, fmt));
209
210 /*
211 * Avoid doing this on valid arguments, walking the prototype
212 * chain can be quite slow.
213 */
214 } else if (Signature.isSignature(signature, [1, 0])) {
215 throw (new Error('signature was created by too old ' +
216 'a version of sshpk and cannot be verified'));
217
218 } else {
219 throw (new TypeError('signature must be a string, ' +
220 'Buffer, or Signature object'));
221 }
222 };
223 return (v);
224};
225
226Key.prototype.createDiffieHellman = function () {
227 if (this.type === 'rsa')
228 throw (new Error('RSA keys do not support Diffie-Hellman'));
229
230 return (new DiffieHellman(this));
231};
232Key.prototype.createDH = Key.prototype.createDiffieHellman;
233
234Key.parse = function (data, format, options) {
235 if (typeof (data) !== 'string')
236 assert.buffer(data, 'data');
237 if (format === undefined)
238 format = 'auto';
239 assert.string(format, 'format');
240 if (typeof (options) === 'string')
241 options = { filename: options };
242 assert.optionalObject(options, 'options');
243 if (options === undefined)
244 options = {};
245 assert.optionalString(options.filename, 'options.filename');
246 if (options.filename === undefined)
247 options.filename = '(unnamed)';
248
249 assert.object(formats[format], 'formats[format]');
250
251 try {
252 var k = formats[format].read(data, options);
253 if (k instanceof PrivateKey)
254 k = k.toPublic();
255 if (!k.comment)
256 k.comment = options.filename;
257 return (k);
258 } catch (e) {
259 if (e.name === 'KeyEncryptedError')
260 throw (e);
261 throw (new KeyParseError(options.filename, format, e));
262 }
263};
264
265Key.isKey = function (obj, ver) {
266 return (utils.isCompatible(obj, Key, ver));
267};
268
269/*
270 * API versions for Key:
271 * [1,0] -- initial ver, may take Signature for createVerify or may not
272 * [1,1] -- added pkcs1, pkcs8 formats
273 * [1,2] -- added auto, ssh-private, openssh formats
274 * [1,3] -- added defaultHashAlgorithm
275 * [1,4] -- added ed support, createDH
276 * [1,5] -- first explicitly tagged version
277 * [1,6] -- changed ed25519 part names
278 * [1,7] -- spki hash types
279 */
280Key.prototype._sshpkApiVersion = [1, 7];
281
282Key._oldVersionDetect = function (obj) {
283 assert.func(obj.toBuffer);
284 assert.func(obj.fingerprint);
285 if (obj.createDH)
286 return ([1, 4]);
287 if (obj.defaultHashAlgorithm)
288 return ([1, 3]);
289 if (obj.formats['auto'])
290 return ([1, 2]);
291 if (obj.formats['pkcs1'])
292 return ([1, 1]);
293 return ([1, 0]);
294};
Note: See TracBrowser for help on using the repository browser.