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