You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

124 lines
3.4 KiB

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