[6a3a178] | 1 | // Copyright 2018 Joyent, Inc.
|
---|
| 2 |
|
---|
| 3 | module.exports = {
|
---|
| 4 | read: read,
|
---|
| 5 | write: write
|
---|
| 6 | };
|
---|
| 7 |
|
---|
| 8 | var assert = require('assert-plus');
|
---|
| 9 | var Buffer = require('safer-buffer').Buffer;
|
---|
| 10 | var utils = require('../utils');
|
---|
| 11 | var Key = require('../key');
|
---|
| 12 | var PrivateKey = require('../private-key');
|
---|
| 13 |
|
---|
| 14 | var pem = require('./pem');
|
---|
| 15 | var ssh = require('./ssh');
|
---|
| 16 | var rfc4253 = require('./rfc4253');
|
---|
| 17 | var dnssec = require('./dnssec');
|
---|
| 18 | var putty = require('./putty');
|
---|
| 19 |
|
---|
| 20 | var DNSSEC_PRIVKEY_HEADER_PREFIX = 'Private-key-format: v1';
|
---|
| 21 |
|
---|
| 22 | function read(buf, options) {
|
---|
| 23 | if (typeof (buf) === 'string') {
|
---|
| 24 | if (buf.trim().match(/^[-]+[ ]*BEGIN/))
|
---|
| 25 | return (pem.read(buf, options));
|
---|
| 26 | if (buf.match(/^\s*ssh-[a-z]/))
|
---|
| 27 | return (ssh.read(buf, options));
|
---|
| 28 | if (buf.match(/^\s*ecdsa-/))
|
---|
| 29 | return (ssh.read(buf, options));
|
---|
| 30 | if (buf.match(/^putty-user-key-file-2:/i))
|
---|
| 31 | return (putty.read(buf, options));
|
---|
| 32 | if (findDNSSECHeader(buf))
|
---|
| 33 | return (dnssec.read(buf, options));
|
---|
| 34 | buf = Buffer.from(buf, 'binary');
|
---|
| 35 | } else {
|
---|
| 36 | assert.buffer(buf);
|
---|
| 37 | if (findPEMHeader(buf))
|
---|
| 38 | return (pem.read(buf, options));
|
---|
| 39 | if (findSSHHeader(buf))
|
---|
| 40 | return (ssh.read(buf, options));
|
---|
| 41 | if (findPuTTYHeader(buf))
|
---|
| 42 | return (putty.read(buf, options));
|
---|
| 43 | if (findDNSSECHeader(buf))
|
---|
| 44 | return (dnssec.read(buf, options));
|
---|
| 45 | }
|
---|
| 46 | if (buf.readUInt32BE(0) < buf.length)
|
---|
| 47 | return (rfc4253.read(buf, options));
|
---|
| 48 | throw (new Error('Failed to auto-detect format of key'));
|
---|
| 49 | }
|
---|
| 50 |
|
---|
| 51 | function findPuTTYHeader(buf) {
|
---|
| 52 | var offset = 0;
|
---|
| 53 | while (offset < buf.length &&
|
---|
| 54 | (buf[offset] === 32 || buf[offset] === 10 || buf[offset] === 9))
|
---|
| 55 | ++offset;
|
---|
| 56 | if (offset + 22 <= buf.length &&
|
---|
| 57 | buf.slice(offset, offset + 22).toString('ascii').toLowerCase() ===
|
---|
| 58 | 'putty-user-key-file-2:')
|
---|
| 59 | return (true);
|
---|
| 60 | return (false);
|
---|
| 61 | }
|
---|
| 62 |
|
---|
| 63 | function findSSHHeader(buf) {
|
---|
| 64 | var offset = 0;
|
---|
| 65 | while (offset < buf.length &&
|
---|
| 66 | (buf[offset] === 32 || buf[offset] === 10 || buf[offset] === 9))
|
---|
| 67 | ++offset;
|
---|
| 68 | if (offset + 4 <= buf.length &&
|
---|
| 69 | buf.slice(offset, offset + 4).toString('ascii') === 'ssh-')
|
---|
| 70 | return (true);
|
---|
| 71 | if (offset + 6 <= buf.length &&
|
---|
| 72 | buf.slice(offset, offset + 6).toString('ascii') === 'ecdsa-')
|
---|
| 73 | return (true);
|
---|
| 74 | return (false);
|
---|
| 75 | }
|
---|
| 76 |
|
---|
| 77 | function findPEMHeader(buf) {
|
---|
| 78 | var offset = 0;
|
---|
| 79 | while (offset < buf.length &&
|
---|
| 80 | (buf[offset] === 32 || buf[offset] === 10))
|
---|
| 81 | ++offset;
|
---|
| 82 | if (buf[offset] !== 45)
|
---|
| 83 | return (false);
|
---|
| 84 | while (offset < buf.length &&
|
---|
| 85 | (buf[offset] === 45))
|
---|
| 86 | ++offset;
|
---|
| 87 | while (offset < buf.length &&
|
---|
| 88 | (buf[offset] === 32))
|
---|
| 89 | ++offset;
|
---|
| 90 | if (offset + 5 > buf.length ||
|
---|
| 91 | buf.slice(offset, offset + 5).toString('ascii') !== 'BEGIN')
|
---|
| 92 | return (false);
|
---|
| 93 | return (true);
|
---|
| 94 | }
|
---|
| 95 |
|
---|
| 96 | function findDNSSECHeader(buf) {
|
---|
| 97 | // private case first
|
---|
| 98 | if (buf.length <= DNSSEC_PRIVKEY_HEADER_PREFIX.length)
|
---|
| 99 | return (false);
|
---|
| 100 | var headerCheck = buf.slice(0, DNSSEC_PRIVKEY_HEADER_PREFIX.length);
|
---|
| 101 | if (headerCheck.toString('ascii') === DNSSEC_PRIVKEY_HEADER_PREFIX)
|
---|
| 102 | return (true);
|
---|
| 103 |
|
---|
| 104 | // public-key RFC3110 ?
|
---|
| 105 | // 'domain.com. IN KEY ...' or 'domain.com. IN DNSKEY ...'
|
---|
| 106 | // skip any comment-lines
|
---|
| 107 | if (typeof (buf) !== 'string') {
|
---|
| 108 | buf = buf.toString('ascii');
|
---|
| 109 | }
|
---|
| 110 | var lines = buf.split('\n');
|
---|
| 111 | var line = 0;
|
---|
| 112 | /* JSSTYLED */
|
---|
| 113 | while (lines[line].match(/^\;/))
|
---|
| 114 | line++;
|
---|
| 115 | if (lines[line].toString('ascii').match(/\. IN KEY /))
|
---|
| 116 | return (true);
|
---|
| 117 | if (lines[line].toString('ascii').match(/\. IN DNSKEY /))
|
---|
| 118 | return (true);
|
---|
| 119 | return (false);
|
---|
| 120 | }
|
---|
| 121 |
|
---|
| 122 | function write(key, options) {
|
---|
| 123 | throw (new Error('"auto" format cannot be used for writing'));
|
---|
| 124 | }
|
---|