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
 | #!/usr/bin/env node
 | ||||||
| 'use strict'; | 'use strict'; | ||||||
|  | 
 | ||||||
| var fs = require('fs'); | var fs = require('fs'); | ||||||
|  | var Rasha = require('../index.js'); | ||||||
|  | 
 | ||||||
| var infile = process.argv[2]; | var infile = process.argv[2]; | ||||||
|  | var format = process.argv[3]; | ||||||
| 
 | 
 | ||||||
| var pem = fs.readFileSync(infile, 'ascii'); | var key = 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 ELOOP = "uASN1.js Error: iterated over 100+ elements (probably a malformed file)"; | try { | ||||||
| var EDEEP = "uASN1.js Error: element nested 100+ layers deep (probably a malformed file)"; |   key = JSON.parse(key); | ||||||
| var ASN1 = require('../lib/uasn1.js'); | } catch(e) { | ||||||
| /* |   // ignore
 | ||||||
| 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; |  | ||||||
| } | } | ||||||
| */ |  | ||||||
| 
 | 
 | ||||||
| var asn1 = ASN1.parse(buf); | if ('string' === typeof key) { | ||||||
| var ws = ''; |   var pub = (-1 !== [ 'public', 'spki', 'pkix' ].indexOf(format)); | ||||||
| function write(asn1) { |   Rasha.import({ pem: key, public: (pub || format) }).then(function (jwk) { | ||||||
|   console.log(ws, 'ch', Buffer.from([asn1.type]).toString('hex'), asn1.length); |     console.log(JSON.stringify(jwk, null, 2)); | ||||||
|   if (!asn1.children) { |   }).catch(function (err) { | ||||||
|     return; |     console.error(err); | ||||||
|   } |     process.exit(1); | ||||||
|   asn1.children.forEach(function (a, i) { |   }); | ||||||
|     ws += '\t'; | } else { | ||||||
|     write(a); |   Rasha.export({ jwk: key, format: format }).then(function (pem) { | ||||||
|     ws = ws.slice(1); |     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'; | '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() { | 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) { | ASN1.parse = function parseAsn1(buf, depth) { | ||||||
|   console.log(''); |   if (depth >= 10) { throw new Error(ASN1.EDEEP); } | ||||||
|   if (depth >= 100) { throw new Error(EDEEP); } |  | ||||||
| 
 | 
 | ||||||
|   var index = 2; // we know, at minimum, data starts after type (0) and lengthSize (1)
 |   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] }; |   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.
 |   // 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.
 |   // 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)) { |   if (0x00 === buf[index] && (0x02 === asn1.type || 0x03 === asn1.type)) { | ||||||
|     console.log('chomp'); |  | ||||||
|     index += 1; |     index += 1; | ||||||
|     adjust = -1; |     adjust = -1; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // this is a primitive value type
 |   // 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); |     asn1.value = buf.slice(index, index + asn1.length + adjust); | ||||||
|     return asn1; |     return asn1; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   asn1.children = []; |   asn1.children = []; | ||||||
|   while (iters < 100 && index < buf.byteLength) { |   while (iters < 15 && index < buf.byteLength) { | ||||||
|     iters += 1; |     iters += 1; | ||||||
|     child = ASN1.parse(buf.slice(index, index + asn1.length), (depth || 0) + 1); |     child = ASN1.parse(buf.slice(index, index + asn1.length), (depth || 0) + 1); | ||||||
|     index += (2 + child.lengthSize + child.length); |     index += (2 + child.lengthSize + child.length); | ||||||
|     asn1.children.push(child); |     asn1.children.push(child); | ||||||
|   } |   } | ||||||
|   if (iters >= 100) { throw new Error(ELOOP); } |   if (iters >= 15) { throw new Error(ASN1.ELOOP); } | ||||||
| 
 | 
 | ||||||
|   return asn1; |   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'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| var RSA = module.exports; | 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