'use strict'; var SSH = module.exports; var Enc = require('./encoding.js'); SSH.parse = function (ssh) { ssh = ssh.split(/\s+/g); var result = { type: ssh[0], jwk: null, comment: ssh[2] || '' }; var buf = Enc.base64ToBuf(ssh[1]); var els = SSH.parseElements(buf); var typ = Enc.bufToBin(els[0]); var len; // RSA keys are all the same if (SSH.types.rsa === typ) { result.jwk = { kty: 'RSA' , n: Enc.bufToUrlBase64(els[2]) , e: Enc.bufToUrlBase64(els[1]) }; return result; } // EC keys are each different if (SSH.types.p256 === typ) { len = 32; result.jwk = { kty: 'EC', crv: 'P-256' }; } else if (SSH.types.p384 === typ) { len = 48; result.jwk = { kty: 'EC', crv: 'P-384' }; } else { throw new Error("Unsupported ssh public key type: " + Enc.bufToBin(els[0])); } // els[1] is just a repeat of a subset of els[0] var x = els[2].slice(1, 1 + len); var y = els[2].slice(1 + len, 1 + len + len); // I don't think EC keys use 0x00 padding, but just in case if (0x00 === x[0]) { x = x.slice(1); } if (0x00 === y[0]) { y = y.slice(1); } result.jwk.x = Enc.bufToUrlBase64(x); result.jwk.y = Enc.bufToUrlBase64(y); return result; }; SSH.parseElements = function (buf) { var fulllen = buf.byteLength || buf.length; var offset = (buf.byteOffset || 0); var i = 0; var index = 0; // using dataview to be browser-compatible (I do want _some_ code reuse) var dv = new DataView(buf.buffer.slice(offset, offset + fulllen)); var els = []; var el; var len; while (index < fulllen) { i += 1; if (i > 15) { throw new Error("15+ elements, probably not a public ssh key"); } len = dv.getUint32(index, false); index += 4; el = buf.slice(index, index + len); // remove BigUInt '00' prefix if (0x00 === el[0]) { el = el.slice(1); } els.push(el); index += len; } if (fulllen !== index) { throw new Error(els.map(function (b) { return Enc.bufToHex(b); }).join('\n') + "invalid ssh public key length"); } return els; }; SSH.types = { // 19 '00000013' // e c d s a - s h a 2 - n i s t p 2 5 6 // 65636473612d736861322d6e69737470323536 // 6e69737470323536 p256: 'ecdsa-sha2-nistp256' // 19 '00000013' // e c d s a - s h a 2 - n i s t p 3 8 4 // 65636473612d736861322d6e69737470333834 // 6e69737470323536 , p384: 'ecdsa-sha2-nistp384' // 7 '00000007' // s s h - r s a // 7373682d727361 , rsa: 'ssh-rsa' };