1 // Copyright 2015 Joyent, Inc.
4 read: read.bind(undefined, false, undefined),
5 readType: read.bind(undefined, false),
7 /* semi-private api, used by sshpk-agent */
8 readPartial: read.bind(undefined, true),
10 /* shared with ssh format */
12 keyTypeToAlg: keyTypeToAlg,
13 algToKeyType: algToKeyType
16 var assert = require('assert-plus');
17 var algs = require('../algs');
18 var utils = require('../utils');
19 var Key = require('../key');
20 var PrivateKey = require('../private-key');
21 var SSHBuffer = require('../ssh-buffer');
23 function algToKeyType(alg) {
25 if (alg === 'ssh-dss')
27 else if (alg === 'ssh-rsa')
29 else if (alg === 'ssh-ed25519')
31 else if (alg === 'ssh-curve25519')
32 return ('curve25519');
33 else if (alg.match(/^ecdsa-sha2-/))
36 throw (new Error('Unknown algorithm ' + alg));
39 function keyTypeToAlg(key) {
41 if (key.type === 'dsa')
43 else if (key.type === 'rsa')
45 else if (key.type === 'ed25519')
46 return ('ssh-ed25519');
47 else if (key.type === 'curve25519')
48 return ('ssh-curve25519');
49 else if (key.type === 'ecdsa')
50 return ('ecdsa-sha2-' + key.part.curve.data.toString());
52 throw (new Error('Unknown key type ' + key.type));
55 function read(partial, type, buf, options) {
56 if (typeof (buf) === 'string')
57 buf = new Buffer(buf);
58 assert.buffer(buf, 'buf');
62 var parts = key.parts = [];
63 var sshbuf = new SSHBuffer({buffer: buf});
65 var alg = sshbuf.readString();
66 assert.ok(!sshbuf.atEnd(), 'key must have at least one part');
68 key.type = algToKeyType(alg);
70 var partCount = algs.info[key.type].parts.length;
71 if (type && type === 'private')
72 partCount = algs.privInfo[key.type].parts.length;
74 while (!sshbuf.atEnd() && parts.length < partCount)
75 parts.push(sshbuf.readPart());
76 while (!partial && !sshbuf.atEnd())
77 parts.push(sshbuf.readPart());
79 assert.ok(parts.length >= 1,
80 'key must have at least one part');
81 assert.ok(partial || sshbuf.atEnd(),
82 'leftover bytes at end of key');
84 var Constructor = Key;
85 var algInfo = algs.info[key.type];
86 if (type === 'private' || algInfo.parts.length !== parts.length) {
87 algInfo = algs.privInfo[key.type];
88 Constructor = PrivateKey;
90 assert.strictEqual(algInfo.parts.length, parts.length);
92 if (key.type === 'ecdsa') {
93 var res = /^ecdsa-sha2-(.+)$/.exec(alg);
94 assert.ok(res !== null);
95 assert.strictEqual(res[1], parts[0].data.toString());
98 var normalized = true;
99 for (var i = 0; i < algInfo.parts.length; ++i) {
100 parts[i].name = algInfo.parts[i];
101 if (parts[i].name !== 'curve' &&
102 algInfo.normalize !== false) {
104 var nd = utils.mpNormalize(p.data);
113 key._rfc4253Cache = sshbuf.toBuffer();
115 if (partial && typeof (partial) === 'object') {
116 partial.remainder = sshbuf.remainder();
117 partial.consumed = sshbuf._offset;
120 return (new Constructor(key));
123 function write(key, options) {
126 var alg = keyTypeToAlg(key);
129 var algInfo = algs.info[key.type];
130 if (PrivateKey.isPrivateKey(key))
131 algInfo = algs.privInfo[key.type];
132 var parts = algInfo.parts;
134 var buf = new SSHBuffer({});
136 buf.writeString(alg);
138 for (i = 0; i < parts.length; ++i) {
139 var data = key.part[parts[i]].data;
140 if (algInfo.normalize !== false)
141 data = utils.mpNormalize(data);
142 buf.writeBuffer(data);
145 return (buf.toBuffer());