a squeaky clean start
This commit is contained in:
		
							parent
							
								
									5917757dfb
								
							
						
					
					
						commit
						8d2ebe77fe
					
				
							
								
								
									
										89
									
								
								bin/rasha.js
									
									
									
									
									
								
							
							
						
						
									
										89
									
								
								bin/rasha.js
									
									
									
									
									
								
							@ -1,76 +1,33 @@
 | 
			
		||||
#!/usr/bin/env node
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var fs = require('fs');
 | 
			
		||||
var Rasha = require('../index.js');
 | 
			
		||||
 | 
			
		||||
var infile = process.argv[2];
 | 
			
		||||
var format = process.argv[3];
 | 
			
		||||
 | 
			
		||||
var pem = fs.readFileSync(infile, 'ascii');
 | 
			
		||||
var b64 = pem.split(/\n/).filter(function (line) {
 | 
			
		||||
  // TODO test if RSA key
 | 
			
		||||
  if (/^---/.test(line)) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  return true;
 | 
			
		||||
}).join('');
 | 
			
		||||
var buf = Buffer.from(b64, 'base64');
 | 
			
		||||
var key = fs.readFileSync(infile, 'ascii');
 | 
			
		||||
 | 
			
		||||
var ELOOP = "uASN1.js Error: iterated over 100+ elements (probably a malformed file)";
 | 
			
		||||
var EDEEP = "uASN1.js Error: element nested 100+ layers deep (probably a malformed file)";
 | 
			
		||||
var ASN1 = require('../lib/uasn1.js');
 | 
			
		||||
/*
 | 
			
		||||
function ASN1(buf, depth) {
 | 
			
		||||
  if (depth >= 100) {
 | 
			
		||||
    throw new Error(EDEEP);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // start after type (0) and lengthSize (1)
 | 
			
		||||
  var index = 2;
 | 
			
		||||
  var asn1 = {
 | 
			
		||||
    type: buf[0]
 | 
			
		||||
  , lengthSize: 0
 | 
			
		||||
  , length: buf[1]
 | 
			
		||||
  };
 | 
			
		||||
  var child;
 | 
			
		||||
  var i = 0;
 | 
			
		||||
  if (0x80 & asn1.length) {
 | 
			
		||||
    asn1.lengthSize = 0x7f & asn1.length;
 | 
			
		||||
    // I think that buf->hex->int solves the problem of Endianness... not sure
 | 
			
		||||
    asn1.length = parseInt(buf.slice(index, index + asn1.lengthSize).toString('hex'), 16);
 | 
			
		||||
    // add back the original byte indicating lengthSize
 | 
			
		||||
    index += 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // this is a primitive value type
 | 
			
		||||
  if (asn1.type <= 0x06) {
 | 
			
		||||
    i += 1;
 | 
			
		||||
    asn1.value = buf.slice(index, index + asn1.length);
 | 
			
		||||
    return asn1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  asn1.children = [];
 | 
			
		||||
  while (i < 100 && index < buf.byteLength) {
 | 
			
		||||
    child = ASN1(buf.slice(index), (depth || 0) + 1);
 | 
			
		||||
    index += (2 + child.lengthSize + child.length);
 | 
			
		||||
    asn1.children.push(child);
 | 
			
		||||
  }
 | 
			
		||||
  if (i >= 100) { throw new Error(ELOOP); }
 | 
			
		||||
 | 
			
		||||
  return asn1;
 | 
			
		||||
try {
 | 
			
		||||
  key = JSON.parse(key);
 | 
			
		||||
} catch(e) {
 | 
			
		||||
  // ignore
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
var asn1 = ASN1.parse(buf);
 | 
			
		||||
var ws = '';
 | 
			
		||||
function write(asn1) {
 | 
			
		||||
  console.log(ws, 'ch', Buffer.from([asn1.type]).toString('hex'), asn1.length);
 | 
			
		||||
  if (!asn1.children) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  asn1.children.forEach(function (a, i) {
 | 
			
		||||
    ws += '\t';
 | 
			
		||||
    write(a);
 | 
			
		||||
    ws = ws.slice(1);
 | 
			
		||||
if ('string' === typeof key) {
 | 
			
		||||
  var pub = (-1 !== [ 'public', 'spki', 'pkix' ].indexOf(format));
 | 
			
		||||
  Rasha.import({ pem: key, public: (pub || format) }).then(function (jwk) {
 | 
			
		||||
    console.log(JSON.stringify(jwk, null, 2));
 | 
			
		||||
  }).catch(function (err) {
 | 
			
		||||
    console.error(err);
 | 
			
		||||
    process.exit(1);
 | 
			
		||||
  });
 | 
			
		||||
} else {
 | 
			
		||||
  Rasha.export({ jwk: key, format: format }).then(function (pem) {
 | 
			
		||||
    console.log(pem);
 | 
			
		||||
  }).catch(function (err) {
 | 
			
		||||
    console.error(err);
 | 
			
		||||
    process.exit(2);
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
console.log(JSON.stringify(asn1, null, 2));
 | 
			
		||||
//console.log(asn1);
 | 
			
		||||
write(asn1);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								index.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
module.exports = require('./lib/rasha.js');
 | 
			
		||||
@ -1,18 +1,16 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var ELOOP = "uASN1.js Error: iterated over 100+ elements (probably a malformed file)";
 | 
			
		||||
var EDEEP = "uASN1.js Error: element nested 100+ layers deep (probably a malformed file)";
 | 
			
		||||
// Container Types are Sequence 0x30, Octect String 0x04, Array? (0xA0, 0xA1)
 | 
			
		||||
// Value Types are Integer 0x02, Bit String 0x03, Null 0x05, Object ID 0x06,
 | 
			
		||||
// Sometimes Bit String is used as a container (RSA Pub Spki)
 | 
			
		||||
var VTYPES = [ 0x02, 0x03, 0x05, 0x06 ];
 | 
			
		||||
 | 
			
		||||
var ASN1 = module.exports = function ASN1() {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
ASN1.ELOOP = "uASN1.js Error: iterated over 15+ elements (probably a malformed file)";
 | 
			
		||||
ASN1.EDEEP = "uASN1.js Error: element nested 10+ layers deep (probably a malformed file)";
 | 
			
		||||
// Container Types are Sequence 0x30, Octect String 0x04, Array? (0xA0, 0xA1)
 | 
			
		||||
// Value Types are Integer 0x02, Bit String 0x03, Null 0x05, Object ID 0x06,
 | 
			
		||||
// Sometimes Bit String is used as a container (RSA Pub Spki)
 | 
			
		||||
ASN1.VTYPES = [ 0x02, 0x03, 0x05, 0x06 ];
 | 
			
		||||
ASN1.parse = function parseAsn1(buf, depth) {
 | 
			
		||||
  console.log('');
 | 
			
		||||
  if (depth >= 100) { throw new Error(EDEEP); }
 | 
			
		||||
  if (depth >= 10) { throw new Error(ASN1.EDEEP); }
 | 
			
		||||
 | 
			
		||||
  var index = 2; // we know, at minimum, data starts after type (0) and lengthSize (1)
 | 
			
		||||
  var asn1 = { type: buf[0], lengthSize: 0, length: buf[1] };
 | 
			
		||||
@ -30,27 +28,25 @@ ASN1.parse = function parseAsn1(buf, depth) {
 | 
			
		||||
 | 
			
		||||
  // High-order bit Integers have a leading 0x00 to signify that they are positive.
 | 
			
		||||
  // Bit Streams use the first byte to signify padding, which x.509 doesn't use.
 | 
			
		||||
  console.log(buf[index], asn1.type);
 | 
			
		||||
  if (0x00 === buf[index] && (0x02 === asn1.type || 0x03 === asn1.type)) {
 | 
			
		||||
    console.log('chomp');
 | 
			
		||||
    index += 1;
 | 
			
		||||
    adjust = -1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // this is a primitive value type
 | 
			
		||||
  if (-1 !== VTYPES.indexOf(asn1.type)) {
 | 
			
		||||
  if (-1 !== ASN1.VTYPES.indexOf(asn1.type)) {
 | 
			
		||||
    asn1.value = buf.slice(index, index + asn1.length + adjust);
 | 
			
		||||
    return asn1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  asn1.children = [];
 | 
			
		||||
  while (iters < 100 && index < buf.byteLength) {
 | 
			
		||||
  while (iters < 15 && index < buf.byteLength) {
 | 
			
		||||
    iters += 1;
 | 
			
		||||
    child = ASN1.parse(buf.slice(index, index + asn1.length), (depth || 0) + 1);
 | 
			
		||||
    index += (2 + child.lengthSize + child.length);
 | 
			
		||||
    asn1.children.push(child);
 | 
			
		||||
  }
 | 
			
		||||
  if (iters >= 100) { throw new Error(ELOOP); }
 | 
			
		||||
  if (iters >= 15) { throw new Error(ASN1.ELOOP); }
 | 
			
		||||
 | 
			
		||||
  return asn1;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										56
									
								
								lib/encoding.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								lib/encoding.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,56 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var Enc = module.exports;
 | 
			
		||||
 | 
			
		||||
Enc.bufToHex = function toHex(u8) {
 | 
			
		||||
  var hex = [];
 | 
			
		||||
  var i, h;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < u8.byteLength; i += 1) {
 | 
			
		||||
    h = u8[i].toString(16);
 | 
			
		||||
    if (2 !== h.length) { h = '0' + h; }
 | 
			
		||||
    hex.push(h);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return hex.join('').toLowerCase();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Enc.strToBin = function strToBin(str) {
 | 
			
		||||
  var escstr = encodeURIComponent(str);
 | 
			
		||||
  // replaces any uri escape sequence, such as %0A,
 | 
			
		||||
  // with binary escape, such as 0x0A
 | 
			
		||||
  var binstr = escstr.replace(/%([0-9A-F]{2})/g, function(match, p1) {
 | 
			
		||||
    return String.fromCharCode(parseInt(p1, 16));
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return binstr;
 | 
			
		||||
};
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Enc.strToBase64 = function strToBase64(str) {
 | 
			
		||||
	// node automatically can tell the difference
 | 
			
		||||
	// between uc2 (utf-8) strings and binary strings
 | 
			
		||||
	// so we don't have to re-encode the strings
 | 
			
		||||
	return Buffer.from(str).toString('base64');
 | 
			
		||||
};
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Enc.urlBase64ToBase64 = function urlsafeBase64ToBase64(str) {
 | 
			
		||||
  var r = str % 4;
 | 
			
		||||
  if (2 === r) {
 | 
			
		||||
    str += '==';
 | 
			
		||||
  } else if (3 === r) {
 | 
			
		||||
    str += '=';
 | 
			
		||||
  }
 | 
			
		||||
  return str.replace(/-/g, '+').replace(/_/g, '/');
 | 
			
		||||
};
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
Enc.base64ToBuf = function base64ToBuf(str) {
 | 
			
		||||
	// always convert from urlsafe base64, just in case
 | 
			
		||||
	//return Buffer.from(Enc.urlBase64ToBase64(str)).toString('base64');
 | 
			
		||||
	return Buffer.from(str, 'base64');
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										39
									
								
								lib/pem.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								lib/pem.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var PEM = module.exports;
 | 
			
		||||
var Enc = require('./encoding.js');
 | 
			
		||||
 | 
			
		||||
PEM.RSA_OBJID = '06 09 2A864886F70D010101'
 | 
			
		||||
  .replace(/\s+/g, '').toLowerCase();
 | 
			
		||||
 | 
			
		||||
PEM.parseBlock = function pemToDer(pem) {
 | 
			
		||||
  var typ;
 | 
			
		||||
  var pub;
 | 
			
		||||
  var hex;
 | 
			
		||||
  var der = Enc.base64ToBuf(pem.split(/\n/).filter(function (line, i) {
 | 
			
		||||
    if (0 === i) {
 | 
			
		||||
      if (/ PUBLIC /.test(line)) {
 | 
			
		||||
        pub = true;
 | 
			
		||||
      } else if (/ PRIVATE /.test(line)) {
 | 
			
		||||
        pub = false;
 | 
			
		||||
      }
 | 
			
		||||
      if (/ RSA /.test(line)) {
 | 
			
		||||
        typ = 'RSA';
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return !/---/.test(line);
 | 
			
		||||
  }).join(''));
 | 
			
		||||
 | 
			
		||||
  if (!typ) {
 | 
			
		||||
    hex = Enc.bufToHex(der);
 | 
			
		||||
    if (-1 !== hex.indexOf(PEM.RSA_OBJID)) {
 | 
			
		||||
      typ = 'RSA';
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if (!typ) {
 | 
			
		||||
    console.warn("Definitely not an RSA PKCS#8 because there's no RSA Object ID in the DER body.");
 | 
			
		||||
    console.warn("Probably not an RSA PKCS#1 because 'RSA' wasn't in the PEM type string.");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return { kty: typ, pub: pub, der: der };
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										56
									
								
								lib/rasha.js
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								lib/rasha.js
									
									
									
									
									
								
							@ -1,3 +1,59 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var RSA = module.exports;
 | 
			
		||||
var ASN1 = require('./asn1.js');
 | 
			
		||||
//var Enc = require('./encoding.js');
 | 
			
		||||
var PEM = require('./pem.js');
 | 
			
		||||
var SSH = require('./ssh.js');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
RSAPrivateKey ::= SEQUENCE {
 | 
			
		||||
  version           Version,
 | 
			
		||||
  modulus           INTEGER,  -- n
 | 
			
		||||
  publicExponent    INTEGER,  -- e
 | 
			
		||||
  privateExponent   INTEGER,  -- d
 | 
			
		||||
  prime1            INTEGER,  -- p
 | 
			
		||||
  prime2            INTEGER,  -- q
 | 
			
		||||
  exponent1         INTEGER,  -- d mod (p-1)
 | 
			
		||||
  exponent2         INTEGER,  -- d mod (q-1)
 | 
			
		||||
  coefficient       INTEGER,  -- (inverse of q) mod p
 | 
			
		||||
  otherPrimeInfos   OtherPrimeInfos OPTIONAL
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/*global Promise*/
 | 
			
		||||
RSA.parse = function parseEc(opts) {
 | 
			
		||||
  return Promise.resolve().then(function () {
 | 
			
		||||
    if (!opts || !opts.pem || 'string' !== typeof opts.pem) {
 | 
			
		||||
      throw new Error("must pass { pem: pem } as a string");
 | 
			
		||||
    }
 | 
			
		||||
    if (0 === opts.pem.indexOf('ssh-rsa ')) {
 | 
			
		||||
      return SSH.parse(opts.pem);
 | 
			
		||||
    }
 | 
			
		||||
    var pem = opts.pem;
 | 
			
		||||
    var block = PEM.parseBlock(pem);
 | 
			
		||||
    //var hex = toHex(u8);
 | 
			
		||||
    //var jwk = { kty: 'RSA' };
 | 
			
		||||
 | 
			
		||||
    var asn1 = ASN1.parse(block.der);
 | 
			
		||||
    var ws = '';
 | 
			
		||||
    function write(asn1) {
 | 
			
		||||
      console.log(ws, 'ch', Buffer.from([asn1.type]).toString('hex'), asn1.length);
 | 
			
		||||
      if (!asn1.children) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      asn1.children.forEach(function (a) {
 | 
			
		||||
        ws += '\t';
 | 
			
		||||
        write(a);
 | 
			
		||||
        ws = ws.slice(1);
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    //console.log(JSON.stringify(asn1, null, 2));
 | 
			
		||||
    console.log(asn1);
 | 
			
		||||
    write(asn1);
 | 
			
		||||
 | 
			
		||||
    return { kty: 'RSA' };
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
RSA.toJwk = RSA.import = RSA.parse;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										10
									
								
								lib/ssh.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								lib/ssh.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var SSH = module.exports;
 | 
			
		||||
 | 
			
		||||
                  //  7  s  s  h  -  r  s  a
 | 
			
		||||
SSH.RSA = '00000007 73 73 68 2d 72 73 61'.replace(/\s+/g, '').toLowerCase();
 | 
			
		||||
 | 
			
		||||
SSH.parse = function (pem) {
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user