GithubHelp home page GithubHelp logo

digitalbazaar / forge Goto Github PK

View Code? Open in Web Editor NEW
5.0K 149.0 761.0 4.95 MB

A native implementation of TLS in Javascript and tools to write crypto-based and network-heavy webapps

Home Page: https://digitalbazaar.com/

License: Other

JavaScript 93.33% ActionScript 1.47% C 0.76% HTML 4.16% Python 0.20% CSS 0.07%
crypto cryptography x509 message-digest aes asn1 cipher pkcs tls javascript

forge's People

Contributors

aljones15 avatar andersk avatar cadorn avatar davidlehn avatar dhensby avatar dlongley avatar emirotin avatar evanj avatar evgenus avatar fxa avatar hiddentao avatar jduncanator avatar kevincennis avatar lautaroscytl avatar leoselig avatar linuxwolf avatar mattcollier avatar mgcrea avatar msporny avatar mundry avatar renzenicolai avatar siebertm avatar stardast avatar stesie avatar tomds avatar troyfactor4 avatar vbuch avatar vijayp avatar waynesan avatar zachmart avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

forge's Issues

Wrong Server Key Exchange message during Handshake

Apparently for future uses forge has included a Server Key Exchange message sent by the server to the client that is for now always empty, because only RSA is supported.

This empty message is systematically sent by forge's tls server and then refused by usual tls clients (browsers, node), the tls connexion fails.

A possible workaround is to comment rval.putByte and rval.putInt24 in tls.createServerKeyExchange

Problem validation certificates cert chain with differents oids

If I try to validate the certificate chain from a ca with different oid that its child, the validation fail.
The problem is that the parent and child use different oids.

This is my test:
it("validate certificate chain", function() {
var ca = forge.pki.certificateFromPem(CA_CERTIFICATE);
var cer = forge.pki.certificateFromPem(CHILD_CERTIFICATE);
// verify certificate
var caStore = forge.pki.createCaStore();
caStore.addCertificate(ca);
try {
forge.pki.verifyCertificateChain(caStore, [ cer ],
function(vfd, depth, chain) {
expect(vfd).toBe(true);
return vfd;
});
} catch (e) {
expect(false).toBe(true);
}
});

To solve this problem, in the function cert.verify in pki.js, I've modifed this line

var oid = oids[cert.signatureOid];

for this one

oid = oids[child.signatureOid];

The solution is get the oid from the child, not from the parent.

Interest in a patch for RSA-OAEP?

I've been using Forge to provide me with cryptographic primitives so I can communicate with a program written in another programming language. This existing program uses RSA keys with OAEP padding, so I implement it, using forge's primitives. If I were to send a pull request, would you accept this into Forge itself? It isn't useful for SSL/TLS (so maybe that is a no), but it would be useful for others who might want to use Forge to implement other systems (which seems like a bonus to me).

Thanks!

Upload to NPM

Hey,
I just saw this library, and am very interested in using it with nodejs, but the fact that it's not in the NPM repository is a real deal breaker for me, as it makes it harder both for deployment and contributors to use it. It'd be cool if this could be uploaded to NPM.

forge.util.getQueryVariables breaks on malformed URL parameter names

I noticed a problem with forge.util.getQueryVariables():

Once this method is called to split a URL containing malformed parameter names, the method breaks and exposes native DOM objects.

Example:
/testurl.html?constructor=1&proto=2&valueOf=3

Affected Code:

      if(!(key in rval)) {
        rval[key] = [];
      }
      if(val !== null) {
        rval[key].push(unescape(val));
      }

The key value will be used as index for rval. rval is an empty literal - and with key being set to e.g. constructor, we will access the native object constructor - and not the URL parameter as one might expect. This causes a TypeError and the code-flow to stop:

TypeError: rval[key].push is not a function

rval[key].push(unescape(val));

It should be made sure, that the key value undergoes a number of checks before being used as index for the rval array - so no (let's call it) DoS happens via URL parameters.

RSA padding pseudo random numbers

Hi Dave,

Is I have suggested, you substitued your Math.random() call with:
var padBytes = forge.random.getBytes(padNum);
for(var i = 0; i < padNum; ++i) {
eb.putByte(Math.max(1, padBytes.charCodeAt(i)));
}

This is nearly perfect, only the number 1 is twice as often as the others.
Please replace the block above with
variant1
var padBytes = forge.random.getBytes(padNum);
for(var i = 0; i < padNum; ) {
var byte = forge.random.getBytes(1).charCodeAt(0);
if (byte !== 0) {
eb.putByte(byte);
i += 1;
}
}
or variant2
while (padNum > 0) {
var numZeros = 0;
var padBytes = forge.random.getBytes(padNum);
for(var i = 0; i < padNum; ++i) {
var byte = padBytes.charCodeAt(i);
if (byte === 0) {
numZeros += 1;
}
else {
eb.putByte(byte);
}
}
padNum = numZeros;
}
(variant1 is slower, but has less code)
It might be paranoia mode to enforce uniform distributed pseudo random numbers, but, you know, what was paranoia yesterday, is nowadays standard

Franz

Question: can I connect to SSL-enabled IMAP servers using this?

I've been trying to connect to imap.gmail.com:993 using this library and node's net.Socket and can't figure out why it's not working.

I get as far as this:

[socket] Connected to host.
[tls] (handshake) client -> server: /+cร˜๏ฟฝรช`รด'1๏ฟฝยผPVE๏ฟฝHยฆรบ?oยขt`.ยต๏ฟฝ`ร•รป/5
[socket] server -> client: /
[socket] FIN packet received. Disconnecting...
[socket] Connection closed.

The [socket] output is from my Socket event handlers, and the [tls] output is from my forge.tls client object event handlers. When I call tls.handshake() 5 seconds after my socket is connected it tries to do the 'Client Hello' and fails. The server then kills the connection. Wireshark says the packet is malformed:

screen shot 2013-06-21 at 15 15 25

Here's a successful Client Hello when using the openssl command-line client:

screen shot 2013-06-21 at 15 14 57

Here is my TLS client instance:

var tls = forge.tls.createConnection({
  server: false,
  verify: function(connection, verified, depth, certs) {
    return true;
  },
  connected: function(connection) {
    console.log('[tls] connected');
  },
  tlsDataReady: function(connection) {
    var data = connection.tlsData.getBytes();
    console.log('[tls]' +
      (connection.handshaking ? ' (handshake)' : '') +
      ' client -> server: ' + data);
    socket.write(data);
  },
  dataReady: function(connection) {
    // clear data from the server is ready
    var data = connection.data.getBytes();
    console.log('[tls] server -> client: ' + data);
  },
  closed: function() {
    console.log('[tls] disconnected');
  },
  error: function(connection, error) {
    console.log('[tls] uh oh', error);
  }
});

Does anyone know what might be wrong here?

asn1.js - DER encoding of BMPSTRING objects

asn1.toDer() currently does not handle the type BMPSTRING correctly. The following patch adds this functionality (compare to the implementation of fromDer():

--- asn1.js.orig        2013-03-06 16:44:24.772635500 +0100
+++ asn1.js.new 2013-03-06 16:43:41.229875000 +0100
@@ -415,7 +415,11 @@
   }
   // use asn1.value directly
   else {
-    value.putBytes(obj.value);
+    if(obj.type === asn1.Type.BMPSTRING) {
+        for(var i = 0; i < obj.value.length; i ++)
+            value.putInt16(obj.value.charCodeAt(i));
+    } else
+        value.putBytes(obj.value);
   }

   // add tag byte

P12 Keystore aliases - question

Hi,

I'm using Forge to import existing P12 keystores as well as generate new ones. As part of our business logic we required the alias on the safeBags, e.g. the Friendly Name. With our existing implementation, BouncyCastle, this is available as an attribute on each safeBag alongside the localKeyId.

However, with Forge it seems it's only possible to supply the localKeyId, which I've done (code below) but when I reopen the keyStore it appears to be stored in some kind of binary format. I can't work out how to decrypt the friendlyName from this.

    var options = {
            localKeyId : myUtil.toHexAndUpperCase(aliasName),
            generateLocalKeyId : false
    };
    //Create the PKCS#12
    var pkcs12 = forge.pkcs12.toPkcs12Asn1(privateKey, x509Cert, encodedPassword(password), options);

There are references to friendlyName in the code comments, am I missing something or does Forge not support this?

Thanks,
Kevin

Certificate chain with 1 certificate (signed by ca cert in store) fails

If I pass a single certificate in the chain to a client, and that certificate is not a ca certificate but has been signed by a ca certificate, present in the ca store, the verification process fails with 'Certificate basicConstraints indicates the certificate is not a CA'.

Should line 2409 in pki.js be changed to allow this?, so:

' if(!first || chain.length === 0) {'

becomes

'if (!first) {'

I suppose an alternative would be to pass in the ca certificate as part of the chain, though passing multiple certificates has not yet been implemented (in tls.js, function on line 3054)

What is the correct solution to this problem?

Can you please tell me if it is possible to accomplish what the below code is doing in openssl with your module?

Hi,

Can you please tell me if it is possible to accomplish what the below code is doing in openssl with your module?

I'm basically trying to use my own CA which I already created to create and sign a pk12 format compatible S/MIME certificate.

sudo openssl genrsa -out smime.key 2048
sudo openssl req -new -config ../openssl.cnf -key smime.key -out smime.csr
sudo openssl x509 -req -days 365 -in smime.csr -CA ../cacert.pem -CAkey ../private/cakey.pem -set_serial 1 -out smime.crt -setalias "Self Signed SMIME" -addtrust emailProtection -addreject clientAuth -addreject serverAuth -trustout -extfile ../openssl.cnf -extensions mail_ext
sudo openssl pkcs12 -export -in smime.crt -inkey smime.key -out smime.p12

Thank you in advance,
Tony Yustein

Add MAC to PKCS12 object creation

The lack of MacData on PKCS12 objects created by pkcs12.js causes issues when importing these objects into other tools. In the tests included with forge, you have to use openssl pkcs12 -nomacverify. Mac OS Keychain Access refuses to import the object at all.

The below patch adds MacData to all PKCS12 objects by default. It uses HMAC-SHA1 for the MAC, as specified in PKCS#12. The only thing that might be nice to make configurable is the number of iterations in the key derivation; it's currently set statically to 1024.

diff -rupN ./js/pkcs12.js ../../forge-master/js/pkcs12.js
--- ./js/pkcs12.js  2013-01-14 11:24:29.000000000 -0500
+++ ../../forge-master/js/pkcs12.js 2013-01-14 11:29:09.000000000 -0500
@@ -110,7 +110,9 @@ else if(typeof(module) !== 'undefined' &
       asn1: require('./pkcs7asn1')
     },
     pki: require('./pki'),
-    util: require('./util')
+    util: require('./util'),
+    random: require('./random'),
+    hmac: require('./hmac')
   };
   module.exports = forge.pkcs12 = {};
 }
@@ -741,6 +743,37 @@ p12.toPkcs12Asn1 = function(key, cert, p
     ])
   ]);

+  // MacData
+  var sha1 = forge.md.sha1.create();
+  var macSalt = new forge.util.ByteBuffer(forge.random.getBytes(sha1.blockLength));
+  var iter = 1024;
+  var key = p12.generateKey(password || "", macSalt, 3, iter, 20); // 160-bit key
+  var mac = forge.hmac.create();
+  mac.start(sha1, key);
+  mac.update( asn1.toDer(safe).getBytes()); 
+  var macValue = mac.getMac();
+  var macData = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
+    // mac DigestInfo
+    asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
+      // digestAlgorithm
+      asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
+        // algorithm = SHA-1
+        asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, 
+          asn1.oidToDer(oids['sha1']).getBytes()),
+        // parameters = Null
+        asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '')
+      ]),
+      // digest
+      asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, macValue.getBytes())
+    ]),
+    // macSalt OCTET STRING
+    asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, macSalt.getBytes()),
+    // iterations INTEGER (XXX: Only support iter < 65536)
+    asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, 
+      forge.util.hexToBytes( iter.toString(16) )
+    )
+  ]);
+
   // PFX
   return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
     // version (3)
@@ -758,7 +791,8 @@ p12.toPkcs12Asn1 = function(key, cert, p
           asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false,
           asn1.toDer(safe).getBytes())
       ])
-    ])
+    ]),
+    macData
   ]);
 };

Standalone Browser JS file

Is it possible to build just one file that exposes forge at window.forge?

The build script doesn't run on my mac, doesn't find aclocal, so I couldn't find out if that already does that.

Or can I just concatenate files together as I wish?

Besides that I'm using browserify, which does static analysis on node code to get require calls and bundle it up for the server, but because of the multi module system support it can't do that.

Insufficient type checks using obj.constructor

The library uses a specific yet weak pattern for type checks in many places - for instance here (aes.js#832):

  // convert key integer array into byte buffer
  else if(key.constructor == Array &&
    (key.length == 16 || key.length == 24 || key.length == 32)) {

This check is not very reliable and can easily be circumvented:

x = {constructor: String};

console.log(x.constructor == String); // true
console.log(x instanceof String); // false

Is there a specific reason why these kinds of checks are being used? Why not make use of instanceof?

Consolidate and write new tests using mocha

The tests in Forge are lacking and split up using several different libraries (and custom code). They need to be unified and able to be run in both a browser and node.js. We should move all of the tests over to using mocha and write new tests.

Can't access gmail's imap service via forge TLS

I would like to add TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA support.

Could you provide some guidance as to where I might start, and how I might do this?

Update:

I actually need TLS_RSA_WITH_RC4_128_SHA (RC4-SHA) support, as indicated by openssl s_client dump here:

New, TLSv1/SSLv3, Cipher is RC4-SHA
Server public key is 1024 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : RC4-SHA
Session-ID: XXXXX
Session-ID-ctx:
Master-Key: ZZZZZ
Key-Arg : None
Start Time: 1370720335
Timeout : 300 (sec)

This is to create a secure connection to gmail's imap service.

IE11 getRandomValues()

be aware, that IE11 has cryptographic correct random values, but uses
window.msCrypto.getRandomValues() instead of window.crypto.getRandomValues().
Microsoft released yesterday the IE11 preview for Windows 7, so we will get a lot of IE11 users, when MS pushes the IE11 with an window update in some weeks/months.

Could you please modify random.js and prng.js to support msCrypto.getRandomValues().
Be aware, I get a QuotaExceededError, when calling getRandomValues() with an array of about 100kb in IE11 (with Chrome I had no problem with more than 1mb)

Multiple Handshake Messages parsing issue

The message to parse is something like :

16 handshake
0301 version
0d26 length

02 server hello
000026 length (38)
0301 TLS 1.0
515ab0c2 unix time
06d6cb5103d5710221030375ef1e794c6299539bb36f77a70ce331b8 random (28)
00 session id length
002f cipher suite
00 compression method

followed by:

0b certificate
000cf4 length
etc

If we look at the parse methods, there is a length parameter that does not seem to be really used.

For example : parseHelloMessage in the above case will not detect the certificate message and continue parsing the server hello message thinking that it is parsing extensions.

Maybe there should be a check like if (record.fragment.read===length) {don't continue parsing}

The issue might be global, so I prefer to ask.

pkcs7.js - findRecipient

In method pkcs7.js, method findRecipient, the serial number and attributes of the recipients in the PKCS#7 message are compared with those of a given certificate. However, it compares the attributes of the certificate subject and not the certificate issuer.

I believe that line 457, which currently is

   var sAttr = cert.subject.attributes;

should instead be

   var sAttr = cert.issuer.attributes; 

forge.pkcs5.pbkdf2

Hi,

I just noticed forge.pkcs5.pbkdf2 is giving different results than other crypto libs on this tests:

Forge:

var password = 'password';
var salt = '4bcda0d1c689fe465c5b8a817f0ddf3d';
var md = forge.md.sha256.create();
var dkey = forge.pkcs5.pbkdf2(password, salt, 1000, 48, md);
console.log(forge.util.bytesToHex(dkey));
// 9da8a5f4ae605f35e82e5beac5f362df15c4255d88f738d641466a4107f99702f35aa5536799e625bab4db080b11f206

sjcl (default using sha256)

var password = 'password';
var salt = '4bcda0d1c689fe465c5b8a817f0ddf3d';
var bitsalt = sjcl.codec.utf8String.toBits(salt);
var keyhexbits = sjcl.misc.pbkdf2(password, bitsalt, 1000, 384);
console.log(sjcl.codec.hex.fromBits(keyhexbits));
// 9da8a5f4ae605f35e82e5beac5f362df15c4255d88f738d641466a4107f9970238e768e72af29ac89a1b16ff277b31d2

CryptoJS

var password = 'password';
var salt = '4bcda0d1c689fe465c5b8a817f0ddf3d';
var key = CryptoJS.PBKDF2(password, salt, { keySize: 384/32, hasher: CryptoJS.algo.SHA256, iterations: 1000 });
console.log(key.toString());
// 9da8a5f4ae605f35e82e5beac5f362df15c4255d88f738d641466a4107f9970238e768e72af29ac89a1b16ff277b31d2
sjcl match with CryptoJS, Forge match only the first 32 bytes:

9da8a5f4ae605f35e82e5beac5f362df15c4255d88f738d641466a4107f99702

Openssl compatibility

Is RSA-OAEP compatible with openssl's version? I tried the following:

echo "deadbeef" | openssl rsautl -inkey ../tests/crypto/rsa_priv.pem -encrypt | xxd -p

And stored the output. Then I tried to decrypt it:

var rsaPriv = forge.pki.privateKeyFromPem(RSA_PRIV_PEM);
var hexMsg = "34c4553591a93d3836d32ae6c4d28cddff226f6e" ...
var msg = forge.util.hexToBytes(hexMsg);
var plainText = rsaPriv.decrypt(msg, "RSA-OAEP");

where RSA_PRIV_PEM is the private key encoded in a Javascript string variable, and I get a "Invalid RSAES-OAEP padding" error when I try to decrypt it. I looked at the code for forge and the code for openssl's version of RSA-OAEP, and at first blush they seem the same, but I wanted to check here before digging into this in more detail.

Am I doing something obviously wrong, should this work, or was forge never designed to be compatible with the "rsautl" tool from openssl?

Thanks for your help!

[PKCS12] Generated PKCS12 DER unreadable in iOS, works with openssl CLI

Using the code from the test, I created a DER encoded ASN.1 PKCS#12 container. I chose 3des as the algorithm for compatibility, but also tested the other options.
Using the openssl CLI like this: openssl pkcs12 -info -in forgeGenerated.p12 the container is read without any problems. In iOS on the other hand, using SecPKCS12Import I get the error errSecDecode, meaning that the data could not be decoded.

To eliminate errors in the obj-c code as a cause, I also generated a PKCS#12 container with the same certificate and private key on the CLI with openssl. This file was decoded in iOS without any problems.

What could cause this?

When I compare the output of openssl pkcs12 -info -in forgeGenerated.p12 with openssl pkcs12 -info -in openSSLGenerated.p12 I notice a few differences:

  • the openssl-generated version specifies the encryption algos for the certificate bag and the schrouded keybag
  • the forge-generated version doesn't specify any algos

See output below:

openssl generated version:

MAC Iteration 2048
MAC verified OK
PKCS7 Encrypted data: pbeWithSHA1And40BitRC2-CBC, Iteration 2048
Certificate bag
Bag Attributes
    localKeyID: 58 8C A3 ED 1B 3C 4C B1 56 39 97 E1 4F B4 93 16 12 DF 5E 19
subject=/C=NL/ST=a/L=a/O=a/OU=a/CN=a
issuer=/C=NL/ST=a/L=a/O=a/OU=a/CN=a
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
PKCS7 Data
Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 2048
Bag Attributes
    localKeyID: 58 8C A3 ED 1B 3C 4C B1 56 39 97 E1 4F B4 93 16 12 DF 5E 19
Key Attributes: <No Attributes>
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,9D7B97D293D9C389

...
-----END RSA PRIVATE KEY-----

Forge generated version:

MAC Iteration 2048
MAC verified OK
PKCS7 Data
Shrouded Keybag: Bag Attributes
    localKeyID: 9E 67 FF FC 03 DE DF C8 45 63 8C DE C3 32 32 64 A5 BE 0E 63
Key Attributes: <No Attributes>
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,351D4D52DBD1E34D

...
-----END RSA PRIVATE KEY-----
PKCS7 Data
Certificate bag
Bag Attributes
    localKeyID: 9E 67 FF FC 03 DE DF C8 45 63 8C DE C3 32 32 64 A5 BE 0E 63
subject=/C=NL/ST=a/L=a/O=a/OU=a/CN=a
issuer=/C=NL/ST=a/L=a/O=a/OU=a/CN=a
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----

Fails on fragmented messages

When a POST needs to be fragmented, forge throws an error. This is because you accidentally try to call 'splice' on a string when there is no such function. You need to replace lines 3754-3761 in tls.js with:

     while(data.length > tls.MaxFragment)
     {
        records.push(tls.createRecord(
        {
           type: record.type,
           data: forge.util.createBuffer(data.slice(0, tls.MaxFragment))
        }));
    data = data.slice(tls.MaxFragment);
     }

AMD (requirejs/define) compatibility

Looks like the JS modules are intended to be loaded via <script> tags or in nodejs.

I need to load them via requirejs which uses define() from the AMD spec to declare modules.

Any objections to me updating the module wrapping to also support loading via AMD compatible loaders?

I propose the following wrapper (example for pki.js):

(function() {
var deps = {
  aes: './aes',
  asn1: './asn1',
  des: './des',
  md: './md',
  mgf: './mgf',
  pkcs5: './pbkdf2',
  pki: {
    oids: './oids',
    rsa: './rsa'
  },
  pss: './pss',
  random: './random',
  rc2: './rc2',
  util: './util',
  jsbn: './jsbn',
  pkcs12: './pkcs12'
};
var name = "pki";
function init(forge) {


var pki = forge.pki;

...


}
/* ########## Begin module wrapper ########## */
var cjsDefine = null;
if (typeof define !== 'function') {
  // CommonJS -> AMD
  if (typeof exports === "object") {
    cjsDefine = function(ids, init) {
      module.exports = init.apply(null, ids.map(function(id) {
        return require(id);
      }));
    }
  } else
  // <script>
  {
    var forge = window.forge = window.forge || {};
    forge[name] = forge[name] || {};
    init(forge);
  }
}
// AMD
if (cjsDefine || typeof define === 'function') {
  var ids = [];
  var assigns = [];
  function forEachDep(path, deps) {
    function assign(path) {
      var index = ids.length;
      ids.push(deps[path[path.length-1]]);
      assigns.push(function(forge, args) {
        var id;
        while(path.length > 1) {
          id = path.shift();
          forge = forge[id] = forge[id] || {};
        }
        forge[path[0]] = args[index];
      });
    }
    for (var alias in deps) {
      if (typeof deps[alias] === "string") {
        assign(path.concat(alias));
      } else {
        forEachDep(path.concat(alias), deps[alias]);
      }
    }
    return forge;
  }
  forEachDep([], deps);
  (cjsDefine || define)(ids, function() {
    var args = arguments;
    var forge = {};
    assigns.forEach(function(assign) {
      assign(forge, args);
    });
    var exports = forge[name] = forge[name] || {};
    init(forge);
    return exports;
  });
}
})();

I know this is ugly and verbose but seems to be the only way to get compatibility without requiring a loader script nor messing with the existing namespaces.

The above works on nodejs and in the browser via requirejs.

I have not tested loading via <script> tag.

Any other suggestions?

Reverse Certificate Chain Verification

In the current code, certificate chains are verified in the reverse order. The isIssuer call checks to make sure that the argument issued the current object. But these two are swapped when verifying certificates in tls.js. Replace line 4058 with:

      if(error === null && !cert.isIssuer(parent))

How to generate PKCS#7 pem from CRTs

I am looking for an alternative to this:

openssl crl2pkcs7 -nocrl -certfile file1.crt -certfile file2.crt

I tried with

  var p7 = forge.pkcs7.createEnvelopedData();
  p7.addRecipient(cert1);
  p7.addRecipient(cert2);
//not sure about this
  p7.content = forge.util.createBuffer('');
  p7.encrypt();
//////
  console.log(forge.pkcs7.messageToPem(p7));

But I am not sure if is the very same thing.

Regards

Cannot choose the hash algorithm on RSA-OAEP

In rsa.js the scheme can only have values 'RSAES-PKCS1-v1_5', 'RSA-OAEP', 'RSAES-OAEP', 'RAW', 'NONE', 'NULL'

The oaep scheme is automatically calling forge.pkcs1.encode_rsa_oaep(key, m);

pkcs1.js has default hash algorithm set to sha-1. Therefore for me now the only option is to alter the pkcs1.js and set the default to sha-256 (which is good enough for now)

revision controlled .min.js files

I personally think the .min.js files should be left out of revision control. Just add instructions and a script to build them. Is that too much effort for users to handle? Would pre-built versioned downloads be better?

If they are left in, should they be updated with every single source changing commit? That would be a pain to do and cause repo bloat but I think could cause confusion if not done. If constant or per-release .min.js updating is the way forward, then please update the HACKING.md file to spell out the steps needed and when to perform them to keep the .min.js files correct.

Publish to npm!

$ npm install node-forge --save
npm http GET https://registry.npmjs.org/node-forge
npm http 404 https://registry.npmjs.org/node-forge
npm ERR! 404 'node-forge' is not in the npm registry.
npm ERR! 404 You should bug the author to publish it
npm ERR! 404
npm ERR! 404 Maybe try 'npm search forge'
npm ERR! 404
npm ERR! 404 Note that you can also install from a
npm ERR! 404 tarball, folder, or http url, or git url.

publicKeyTo/FromPem issue

Hi,

The following public key pem:

-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALRbNcv5vHKpaRvM53E/Dl4QGGO7CjhsHBld8v6Lgx4I2OGVvNCaAop4
rk2GfMmI48gnGEm+dtWAO7n4FEv9FgtV2xFMyBIQFud0y19Yr6pYfb4L9GIBNTCi
vT/+poRHuDHlIyMk636t0ep4iWKR468az514tKZfyWY8pUsk8apTAgMBAAE=
-----END RSA PUBLIC KEY-----

gives an error if we use publicKeyFromPem.

The same key (modulus: 8bd0a81286858b11f2856ac2f3efd8a5e538b2f851a4c02cc717c94ea52418c587cc69515e46b5381d17cd2299cb4c59fae38250898eab31c9b8acfcf02110a96f0f03442ecd34f1befb0604e1ffbb981848534da9f3f23795ed7df047730cb9dab711722ad6504b893cebda2de4b41123d667474a166eba3ead7df8267dda15) gives with publicKeyToPem:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCL0KgShoWLEfKFasLz79il5Tiy
+FGkwCzHF8lOpSQYxYfMaVFeRrU4HRfNIpnLTFn644JQiY6rMcm4rPzwIRCpbw8D
RC7NNPG++wYE4f+7mBhIU02p8/I3le198EdzDLnatxFyKtZQS4k869ot5LQRI9Zn
R0oWbro+rX34Jn3aFQIDAQAB
-----END PUBLIC KEY-----

But openssl for example does not decode the second one, so probably the first one is correct.

I am wondering if the issue is not affecting certificateToPem too (could it be?), since I am having quite a hard time to make something work while everything looks correct, the only thing that I did not check is to decode a certificate pem with something else than forge.

Regards

Aymeric

Public/private key encryption question

Hello everyone,

first of all, after looking around for encryption libraries, I found that forge is the ideal thing to go with. Great work!

However, I am fairly new to using encryption and I have some questions that are not entirely forge related, but I guess that chances are high to get the best answers on this way from experts.

What I am trying to achieve is a strong public/private key encryption between two nodes on the application level. After generating 2048 bit RSA key pairs this is what I am doing on the encryption side:

  • Generating a random 256 bit AES key with 256 bit IV
  • Encrypting the AES key+IV as RSAES-OAEP using the remote's public key
  • Encrypting the data using the AES key
  • Concatenating the RSA-encrypted AES key+IV with the AES-encrypted data
  • Signing it with the private key of the sender
        publicKey = pki.publicKeyFromPem(publicKey);
        privateKey = pki.privateKeyFromPem(privateKey);
        data = util.encodeUtf8(data);
        var key = random.getBytesSync(AES_BYTES);
        var iv = random.getBytesSync(AES_BYTES);
        var cipher = aes.createEncryptionCipher(key);
        cipher.start(util.createBuffer(iv));
        cipher.update(util.createBuffer(data));
        cipher.finish();
        var enc = publicKey.encrypt(key+iv, "RSA-OAEP")+cipher.output.getBytes();
        var md = sha1.create();
        md.update(enc, 'raw');
        return {
            "enc": enc,
            "sig": privateKey.sign(md)
        };

And on the decryption side:

  • Verifying the raw data against the signature and the remote's public key
  • Decrypting the RSA-encrypted AES key+IV part using the local private key
  • Decrypting the AES-encrypted data using the decrypted AES key+IV
        privateKey = pki.privateKeyFromPem(privateKey);
        publicKey = pki.publicKeyFromPem(publicKey);
        var enc = data["enc"];
        var sig = data["sig"];
        var md = sha1.create();
        md.update(enc, 'raw');
        var verified = publicKey.verify(md.digest().getBytes(), sig);
        var aesData = enc.substring(0,RSA_BYTES);
        enc = enc.substring(RSA_BYTES);
        aesData = privateKey.decrypt(aesData, "RSA-OAEP");
        var key = aesData.substring(0,AES_BYTES);
        var iv = aesData.substring(AES_BYTES);
        var cipher = aes.createDecryptionCipher(key);
        cipher.start(util.createBuffer(iv));
        cipher.update(util.createBuffer(enc));
        cipher.finish();
        return {
            "dec": util.decodeUtf8(cipher.output.getBytes()),
            "ver": verified
        };

Is this the right way to do it?

Cheers

Building into a single file using require.js

Hi,

I saw that forge's modules are loaded conditionally making generating a single file through require build difficult, since require can't handle that:

http://requirejs.org/docs/optimization.html

The reason I need this is because browserify can't resolve the node style require() depencies either and my hope is that requiring a single module might do the trick.

Is there any way to bundle the entire library into a single module?

Thanks

RSA key generation: JSBN 2X faster than Forge?

We've found Forge is pretty slow for generating RSA keys (using Node or Chrome). As a result, I ended up timing both Forge and the original JSBN implementation, and I found that the original JSBN implementation seems to be about 2X faster.

Despite the comments in rsa.js indicating that key generation comes from the original JSBN implementation, the code actually looks fairly different (ignoring the fact that Forge can be used "incrementally"). Is this timing difference expected?

Here are a sample of 20 times (in ms) for generating 2048-bit RSA keys from both JSBN and Forge on my laptop (2 GHz Core i7) using Node. You'll see that while there is significant variation, JSBN is on average about 2X faster.

JSBN:
[3403, 5529, 6393, 1189, 767, 3898, 7517, 3410, 1049, 3038, 8201, 5142, 2418, 2329, 1923, 3308, 3070, 3326, 11834, 4712]
avg: 4122.8

Forge:
[11784, 5503, 4270, 8614, 12066, 25130, 17522, 3664, 20016, 2416, 3170, 11703, 13551, 5465, 9123, 5051, 4271, 10412, 6256, 1181]
avg: 9058.4

Separate encryption library

Have you thought about separating out the various algorithms into a standalone library/libraries? It would be awesome if each algorithm had its own project and package each exposing a uniform interface thus allowing for selective inclusion. Currently there is a ton of encryption libraries and each one is just a featureless blob of algorithms.

Any project that makes use of encryption just includes a file or two, slowly growing their own internal crypto library. It would be awesome if we could just add a git submodule with AES only for example.

Also, if you're interested in speed, asm.js compiled code is just 2x slower than native.

PEM encapsulated header fields

Using the private key below, I get the following error:

Uncaught Invalid PEM format pki.js:1019
pki.pemToDer pki.js:1019
pki.encryptedPrivateKeyFromPem pki.js:3071
pki.decryptRsaPrivateKey pki.js:3105

The key was generated with openssl through Ruby, which includes encapsulated header fields defined in RFC 1421 in the pem file.

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,908A2D85694C80A7BF001D69B48F8974

zZpNVpTuggEHTk0H1RmS9667k7p/mM/3RIyAFx2u82oNdbjI0vj75ug1M6DZHIKT
GK372Xg1ND6Xbz3N7A9Vuhu2ETmd0jv4Knp+5NNfkCpqJit//OeWfCCLLz5WlQ4Z
2YjDl57XEihJXUYq4LABJn95udFUcrKOJcj5Sz6PaiHHKOyx/KC0sil4d+AdIzL6
W4KLVygT5iymFGcWyZcW1GdVeQJAhE2qKfd3HtgvCDNPdBuaTxdGv12KFkiwvM4z
5KzIhBxTSEeFr1Ef8pzi7VRR7ip+0+d9xzNZXqlMt6FfurA+MCBF2Y1mzwyiu0EB
ka9xXQnJPTzkaPGmVDtJdxrbIWGHcYVlC+21Vo+lxJyPBqvMdAczRBslIAkmKW53
Lx/dEL3fKcbFPFoLANosLEk+pAE/Tw+ZGMwDPKrpSFdm3zwfiSlYjJexGxTQXRnp
Ot5bt463Bfio/V7hJDDuKSB65VttuqHJxo3FDNILEd/zu2T9G1mzloZWrUrMQ/nD
gHiYVi4YMNv2FEZmqNSyUMXzOnLxD+I70YArsJ9q21wNTd5cWfnRqh2osZsdeUyw
UTmMH3fBZE/L0JlnAOSsDWjUhvoPY9R/YQ8JjXrSw5BplHVpB6/UEV6MMSDFcbCg
VAo7dze9WWkRTRR+XHPmoyViik5ydJk63Hgf7JaDje2WsGUxGy011FHqsWHMb2MC
zWC2AKYzMwFSoSwwkRu0xMyghq0kR1LagX/qjMIPTcHzJ57EzXs8eZyt6Mw5cjXh
eDPADOZSLNQ/E9YHJNsMQ1/lM3YBakxGvPUBwSQ9ZTpthrcMyZo/9YVnlL6iW1mv
-----END RSA PRIVATE KEY-----

The passphrase for this key is testing if you want to use it for a test case.

isIssuer bug

Another random bug with the implementation of isIssuer in pki.js. You increment 'i' which is the issuer's certificate rather than 'n' the index variable. Change line 1385 to:

     for(var n; rval && n < i.attributes.length; ++n)

We actually make initialization explicit and don't bother with the early exit on our version, but you probably don't have to go that far:

for(var n = 0; n < i.attributes.length; ++n)

Client cert chain not created correctly in tls.createCertificate

In tls.js (specifically tls.createCertificate), the client cert chain appears to not be created correctly if there are multiple certificates. Instead of passing one cert to pemToDer in each pass it uses the entire chain

for(var i = 0; i < cert.length; ++i) {
var der = forge.pki.pemToDer(cert);
...
}

should be (changing cert to cert[i])

for(var i = 0; i < cert.length; ++i) {
var der = forge.pki.pemToDer(cert[i]);
...
}

Here is the currently relevant line

Remark on initModule

Hi again,

In older versions, you were checking window.

I think it was better because now it's not possible without hooking inside node.js to run the same code inside a browser and inside node.js (when you don't want to use node.js's modules, it can look strange but this is what I am doing).

To be clear: it seems more clean to define a window var on a server environment if you want to keep the code as it is inside the browser rather than destroying process properties, module.exports, etc to do so, which have of course side effects on other parts of the code that are using node.

Regards,

Aymeric

`HMAC` output formatting

Using HMAC as follows:

function calcHmac(secret, string) {
    var hm = HMAC.create();
    hm.start('sha256', secret);
    hm.update(string);
    return hm.getMac();
}

I am looking for an output format like:

3B092F18640146103F5F3D19D97109E0AA305D0FD36F917E4AB68334CC7CCD7D

How would I derive this format from the output that hm provides?

RSA encrypt/decrypt issue

Given:

function encryptWithPublicKey(publicKey, data) {
    return UTIL.encode64(PKI.rsa.encrypt(data, publicKey, true));
}
function decryptWithPrivateKey(privateKey, data) {
    return PKI.rsa.decrypt(UTIL.decode64(data), privateKey, false, false);
}

When I run:

var original = "73031ebfe0805ae6f106ffa5a3ec974861a6fc509df7ef6832741fd905cfad19";
var encrypted = encryptWithPublicKey(publicKey, original);
var decrypted = decryptWithPrivateKey(privateKey, encrypted);

decrypted is set to 73031ebfe0805ae6f106ffa5a3ec974861a6fc509df7ef6832741fd905cfad19 but decrypted.length is 129 (not 64 as original.length).

decrypted as char code array is [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 51, 48, 51, 49, 101, 98, 102, 101, 48, 56, 48, 53, 97, 101, 54, 102, 49, 48, 54, 102, 102, 97, 53, 97, 51, 101, 99, 57, 55, 52, 56, 54, 49, 97โ€ฆ].

Looks like there is a bunch of 0 padding. How do I get rid of that using a different flag or is this a bug?

Public key from private (RSA)

When I generate an RSA key pair:

var pair = RSA.generateKeyPair(size, 0x10001);

And keep the private key as:

var pk = ASN1.toDer(PKI.privateKeyToAsn1(pair.privateKey)).getBytes()

How can I derive the public key from pk?

I am assuming I can get the public key for a private key in the first place?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.