Explorar el Código

a squeaky clean start

master
AJ ONeal hace 10 meses
padre
commit
8d2ebe77fe
Se han modificado 7 ficheros con 196 adiciones y 80 borrados
  1. 23
    66
      bin/rasha.js
  2. 2
    0
      index.js
  3. 10
    14
      lib/asn1.js
  4. 56
    0
      lib/encoding.js
  5. 39
    0
      lib/pem.js
  6. 56
    0
      lib/rasha.js
  7. 10
    0
      lib/ssh.js

+ 23
- 66
bin/rasha.js Ver fichero

@@ -1,76 +1,33 @@
1 1
 #!/usr/bin/env node
2 2
 'use strict';
3
-var fs = require('fs');
4
-var infile = process.argv[2];
5
-
6
-var pem = fs.readFileSync(infile, 'ascii');
7
-var b64 = pem.split(/\n/).filter(function (line) {
8
-  // TODO test if RSA key
9
-  if (/^---/.test(line)) {
10
-    return false;
11
-  }
12
-  return true;
13
-}).join('');
14
-var buf = Buffer.from(b64, 'base64');
15
-
16
-var ELOOP = "uASN1.js Error: iterated over 100+ elements (probably a malformed file)";
17
-var EDEEP = "uASN1.js Error: element nested 100+ layers deep (probably a malformed file)";
18
-var ASN1 = require('../lib/uasn1.js');
19
-/*
20
-function ASN1(buf, depth) {
21
-  if (depth >= 100) {
22
-    throw new Error(EDEEP);
23
-  }
24 3
 
25
-  // start after type (0) and lengthSize (1)
26
-  var index = 2;
27
-  var asn1 = {
28
-    type: buf[0]
29
-  , lengthSize: 0
30
-  , length: buf[1]
31
-  };
32
-  var child;
33
-  var i = 0;
34
-  if (0x80 & asn1.length) {
35
-    asn1.lengthSize = 0x7f & asn1.length;
36
-    // I think that buf->hex->int solves the problem of Endianness... not sure
37
-    asn1.length = parseInt(buf.slice(index, index + asn1.lengthSize).toString('hex'), 16);
38
-    // add back the original byte indicating lengthSize
39
-    index += 1;
40
-  }
4
+var fs = require('fs');
5
+var Rasha = require('../index.js');
41 6
 
42
-  // this is a primitive value type
43
-  if (asn1.type <= 0x06) {
44
-    i += 1;
45
-    asn1.value = buf.slice(index, index + asn1.length);
46
-    return asn1;
47
-  }
7
+var infile = process.argv[2];
8
+var format = process.argv[3];
48 9
 
49
-  asn1.children = [];
50
-  while (i < 100 && index < buf.byteLength) {
51
-    child = ASN1(buf.slice(index), (depth || 0) + 1);
52
-    index += (2 + child.lengthSize + child.length);
53
-    asn1.children.push(child);
54
-  }
55
-  if (i >= 100) { throw new Error(ELOOP); }
10
+var key = fs.readFileSync(infile, 'ascii');
56 11
 
57
-  return asn1;
12
+try {
13
+  key = JSON.parse(key);
14
+} catch(e) {
15
+  // ignore
58 16
 }
59
-*/
60 17
 
61
-var asn1 = ASN1.parse(buf);
62
-var ws = '';
63
-function write(asn1) {
64
-  console.log(ws, 'ch', Buffer.from([asn1.type]).toString('hex'), asn1.length);
65
-  if (!asn1.children) {
66
-    return;
67
-  }
68
-  asn1.children.forEach(function (a, i) {
69
-    ws += '\t';
70
-    write(a);
71
-    ws = ws.slice(1);
18
+if ('string' === typeof key) {
19
+  var pub = (-1 !== [ 'public', 'spki', 'pkix' ].indexOf(format));
20
+  Rasha.import({ pem: key, public: (pub || format) }).then(function (jwk) {
21
+    console.log(JSON.stringify(jwk, null, 2));
22
+  }).catch(function (err) {
23
+    console.error(err);
24
+    process.exit(1);
25
+  });
26
+} else {
27
+  Rasha.export({ jwk: key, format: format }).then(function (pem) {
28
+    console.log(pem);
29
+  }).catch(function (err) {
30
+    console.error(err);
31
+    process.exit(2);
72 32
   });
73 33
 }
74
-console.log(JSON.stringify(asn1, null, 2));
75
-//console.log(asn1);
76
-write(asn1);

+ 2
- 0
index.js Ver fichero

@@ -0,0 +1,2 @@
1
+'use strict';
2
+module.exports = require('./lib/rasha.js');

lib/uasn1.js → lib/asn1.js Ver fichero

@@ -1,18 +1,16 @@
1 1
 'use strict';
2 2
 
3
-var ELOOP = "uASN1.js Error: iterated over 100+ elements (probably a malformed file)";
4
-var EDEEP = "uASN1.js Error: element nested 100+ layers deep (probably a malformed file)";
5
-// Container Types are Sequence 0x30, Octect String 0x04, Array? (0xA0, 0xA1)
6
-// Value Types are Integer 0x02, Bit String 0x03, Null 0x05, Object ID 0x06,
7
-// Sometimes Bit String is used as a container (RSA Pub Spki)
8
-var VTYPES = [ 0x02, 0x03, 0x05, 0x06 ];
9
-
10 3
 var ASN1 = module.exports = function ASN1() {
11 4
 };
12 5
 
6
+ASN1.ELOOP = "uASN1.js Error: iterated over 15+ elements (probably a malformed file)";
7
+ASN1.EDEEP = "uASN1.js Error: element nested 10+ layers deep (probably a malformed file)";
8
+// Container Types are Sequence 0x30, Octect String 0x04, Array? (0xA0, 0xA1)
9
+// Value Types are Integer 0x02, Bit String 0x03, Null 0x05, Object ID 0x06,
10
+// Sometimes Bit String is used as a container (RSA Pub Spki)
11
+ASN1.VTYPES = [ 0x02, 0x03, 0x05, 0x06 ];
13 12
 ASN1.parse = function parseAsn1(buf, depth) {
14
-  console.log('');
15
-  if (depth >= 100) { throw new Error(EDEEP); }
13
+  if (depth >= 10) { throw new Error(ASN1.EDEEP); }
16 14
 
17 15
   var index = 2; // we know, at minimum, data starts after type (0) and lengthSize (1)
18 16
   var asn1 = { type: buf[0], lengthSize: 0, length: buf[1] };
@@ -30,27 +28,25 @@ ASN1.parse = function parseAsn1(buf, depth) {
30 28
 
31 29
   // High-order bit Integers have a leading 0x00 to signify that they are positive.
32 30
   // Bit Streams use the first byte to signify padding, which x.509 doesn't use.
33
-  console.log(buf[index], asn1.type);
34 31
   if (0x00 === buf[index] && (0x02 === asn1.type || 0x03 === asn1.type)) {
35
-    console.log('chomp');
36 32
     index += 1;
37 33
     adjust = -1;
38 34
   }
39 35
 
40 36
   // this is a primitive value type
41
-  if (-1 !== VTYPES.indexOf(asn1.type)) {
37
+  if (-1 !== ASN1.VTYPES.indexOf(asn1.type)) {
42 38
     asn1.value = buf.slice(index, index + asn1.length + adjust);
43 39
     return asn1;
44 40
   }
45 41
 
46 42
   asn1.children = [];
47
-  while (iters < 100 && index < buf.byteLength) {
43
+  while (iters < 15 && index < buf.byteLength) {
48 44
     iters += 1;
49 45
     child = ASN1.parse(buf.slice(index, index + asn1.length), (depth || 0) + 1);
50 46
     index += (2 + child.lengthSize + child.length);
51 47
     asn1.children.push(child);
52 48
   }
53
-  if (iters >= 100) { throw new Error(ELOOP); }
49
+  if (iters >= 15) { throw new Error(ASN1.ELOOP); }
54 50
 
55 51
   return asn1;
56 52
 };

+ 56
- 0
lib/encoding.js Ver fichero

@@ -0,0 +1,56 @@
1
+'use strict';
2
+
3
+var Enc = module.exports;
4
+
5
+Enc.bufToHex = function toHex(u8) {
6
+  var hex = [];
7
+  var i, h;
8
+
9
+  for (i = 0; i < u8.byteLength; i += 1) {
10
+    h = u8[i].toString(16);
11
+    if (2 !== h.length) { h = '0' + h; }
12
+    hex.push(h);
13
+  }
14
+
15
+  return hex.join('').toLowerCase();
16
+};
17
+
18
+/*
19
+Enc.strToBin = function strToBin(str) {
20
+  var escstr = encodeURIComponent(str);
21
+  // replaces any uri escape sequence, such as %0A,
22
+  // with binary escape, such as 0x0A
23
+  var binstr = escstr.replace(/%([0-9A-F]{2})/g, function(match, p1) {
24
+    return String.fromCharCode(parseInt(p1, 16));
25
+  });
26
+
27
+  return binstr;
28
+};
29
+*/
30
+
31
+/*
32
+Enc.strToBase64 = function strToBase64(str) {
33
+	// node automatically can tell the difference
34
+	// between uc2 (utf-8) strings and binary strings
35
+	// so we don't have to re-encode the strings
36
+	return Buffer.from(str).toString('base64');
37
+};
38
+*/
39
+
40
+/*
41
+Enc.urlBase64ToBase64 = function urlsafeBase64ToBase64(str) {
42
+  var r = str % 4;
43
+  if (2 === r) {
44
+    str += '==';
45
+  } else if (3 === r) {
46
+    str += '=';
47
+  }
48
+  return str.replace(/-/g, '+').replace(/_/g, '/');
49
+};
50
+*/
51
+
52
+Enc.base64ToBuf = function base64ToBuf(str) {
53
+	// always convert from urlsafe base64, just in case
54
+	//return Buffer.from(Enc.urlBase64ToBase64(str)).toString('base64');
55
+	return Buffer.from(str, 'base64');
56
+};

+ 39
- 0
lib/pem.js Ver fichero

@@ -0,0 +1,39 @@
1
+'use strict';
2
+
3
+var PEM = module.exports;
4
+var Enc = require('./encoding.js');
5
+
6
+PEM.RSA_OBJID = '06 09 2A864886F70D010101'
7
+  .replace(/\s+/g, '').toLowerCase();
8
+
9
+PEM.parseBlock = function pemToDer(pem) {
10
+  var typ;
11
+  var pub;
12
+  var hex;
13
+  var der = Enc.base64ToBuf(pem.split(/\n/).filter(function (line, i) {
14
+    if (0 === i) {
15
+      if (/ PUBLIC /.test(line)) {
16
+        pub = true;
17
+      } else if (/ PRIVATE /.test(line)) {
18
+        pub = false;
19
+      }
20
+      if (/ RSA /.test(line)) {
21
+        typ = 'RSA';
22
+      }
23
+    }
24
+    return !/---/.test(line);
25
+  }).join(''));
26
+
27
+  if (!typ) {
28
+    hex = Enc.bufToHex(der);
29
+    if (-1 !== hex.indexOf(PEM.RSA_OBJID)) {
30
+      typ = 'RSA';
31
+    }
32
+  }
33
+  if (!typ) {
34
+    console.warn("Definitely not an RSA PKCS#8 because there's no RSA Object ID in the DER body.");
35
+    console.warn("Probably not an RSA PKCS#1 because 'RSA' wasn't in the PEM type string.");
36
+  }
37
+
38
+  return { kty: typ, pub: pub, der: der };
39
+};

+ 56
- 0
lib/rasha.js Ver fichero

@@ -1,3 +1,59 @@
1 1
 'use strict';
2 2
 
3 3
 var RSA = module.exports;
4
+var ASN1 = require('./asn1.js');
5
+//var Enc = require('./encoding.js');
6
+var PEM = require('./pem.js');
7
+var SSH = require('./ssh.js');
8
+
9
+
10
+/*
11
+RSAPrivateKey ::= SEQUENCE {
12
+  version           Version,
13
+  modulus           INTEGER,  -- n
14
+  publicExponent    INTEGER,  -- e
15
+  privateExponent   INTEGER,  -- d
16
+  prime1            INTEGER,  -- p
17
+  prime2            INTEGER,  -- q
18
+  exponent1         INTEGER,  -- d mod (p-1)
19
+  exponent2         INTEGER,  -- d mod (q-1)
20
+  coefficient       INTEGER,  -- (inverse of q) mod p
21
+  otherPrimeInfos   OtherPrimeInfos OPTIONAL
22
+}
23
+*/
24
+
25
+/*global Promise*/
26
+RSA.parse = function parseEc(opts) {
27
+  return Promise.resolve().then(function () {
28
+    if (!opts || !opts.pem || 'string' !== typeof opts.pem) {
29
+      throw new Error("must pass { pem: pem } as a string");
30
+    }
31
+    if (0 === opts.pem.indexOf('ssh-rsa ')) {
32
+      return SSH.parse(opts.pem);
33
+    }
34
+    var pem = opts.pem;
35
+    var block = PEM.parseBlock(pem);
36
+    //var hex = toHex(u8);
37
+    //var jwk = { kty: 'RSA' };
38
+
39
+    var asn1 = ASN1.parse(block.der);
40
+    var ws = '';
41
+    function write(asn1) {
42
+      console.log(ws, 'ch', Buffer.from([asn1.type]).toString('hex'), asn1.length);
43
+      if (!asn1.children) {
44
+        return;
45
+      }
46
+      asn1.children.forEach(function (a) {
47
+        ws += '\t';
48
+        write(a);
49
+        ws = ws.slice(1);
50
+      });
51
+    }
52
+    //console.log(JSON.stringify(asn1, null, 2));
53
+    console.log(asn1);
54
+    write(asn1);
55
+
56
+    return { kty: 'RSA' };
57
+  });
58
+};
59
+RSA.toJwk = RSA.import = RSA.parse;

+ 10
- 0
lib/ssh.js Ver fichero

@@ -0,0 +1,10 @@
1
+'use strict';
2
+
3
+var SSH = module.exports;
4
+
5
+                  //  7  s  s  h  -  r  s  a
6
+SSH.RSA = '00000007 73 73 68 2d 72 73 61'.replace(/\s+/g, '').toLowerCase();
7
+
8
+SSH.parse = function (pem) {
9
+
10
+};

Loading…
Cancelar
Guardar