ValidatorException: KeyUsage does not allow key encipherment

Not applicable

I deployed an node app with official FB node sdk.

It works locally, when tested in apigee it returns this in the console.

[Error: sun.security.validator.ValidatorException: KeyUsage does not allow key encipherment]

Same things happen if I try to directly call Facebook Graph.

Solved Solved
0 6 4,500
1 ACCEPTED SOLUTION

Not applicable

Yes, this is a bug in Trireme. It is not using the correct argument to the Java function used to verify the server's certificate, so it is doing more validation than is necessary, and thus generating the error because the "key encipherment" feature is required for an RSA public key, but in this case we are using an ECDHE_ECDSA public key. (The Java documentation is totally unhelpful here BTW.)

I fixed this in the latest build of Trireme, checked in to GitHub, and coming to a Maven snapshot repository soon. No release yet.

Fixing this in the Apigee Cloud will require us to adopt the latest build of Trireme, which will take us some more time. Apigee Support can help escalate this and make it happen more quickly.

Finally, you can work around this by passing the option "rejectUnauthorized: false" when creating a TLS connection or an HTTPS request in Node. This disables all certificate validation, so it is not a good production solution, but it does allow the connection to be made. I'm not sure how to get request to pass this down, however -- that may take more research.

https://nodejs.org/api/https.html#https_https_request_options_callback

https://nodejs.org/api/tls.html#tls_tls_connect_options_callback

View solution in original post

6 REPLIES 6

Hi @Daniel Dimov,

Could you provide some more info on the node modules you're using, and perhaps samples requests - both via Apigee node execution as well as directly to FB?

Not applicable

@Daniel Dimov ,

Apigee uses trireme to run node.js (Trireme runs Node.js scripts inside the JVM).

In most of the cases your local scripts will work as it is on Apigee however there are few differences , mainly Trireme uses SSLengine for TLS/SSL and HTTPS support where as standard Node.js uses OpenSSL.

I tried with a sample facebook API and saw the below when I enabled the debug logs in the message processor.

DEBUG i.a.t.c.m.c.ConnectionImpl - ConnectionImpl.checkPeerAuthorization() : Error verifying SSL peer [Session-6, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA]: {}
sun.security.validator.ValidatorException: KeyUsage does not allow key encipherment

Ran the same script using node and trireme on the same MP and as you said it works well with node and fails with trireme .

Looks like this AES_128_CBC_SHA is causing the issue , Read this link for more information on the ciphers https://www.npmjs.com/package/trireme

I am not sure if this is a bug or some extra settings needed or if this is a known limitation , Will explore more .

Hope some one in the community can shed some light on the issue.

cc @dzuluaga @arghya das @Sandeep Murusupalli

Not applicable

Thanks for the support @Vidya and @Maruti Chand

I'm using the recommended node module from Facebook https://github.com/Thuzi/facebook-node-sdk

var http = require('http');
var FB = require('fb');

var svr = http.createServer(
  function(req, resp) {
   	FB.setAccessToken('MY_TOKEN');

        var body = 'My first post using facebook-node-sdk';
        FB.api('me/feed', 'post', { message: body}, function (res) {
            if(!res || res.error) {
                console.log(!res ? 'error occurred' : res.error);
                return;
            }
        console.log('Post Id: ' + res.id);
        });        resp.end();
    
});

svr.listen(9000, function() {
    console.log('Node HTTP server is listening hi');
});

Also tried with https.createServer result is the same.

Not applicable

Yes, this is a bug in Trireme. It is not using the correct argument to the Java function used to verify the server's certificate, so it is doing more validation than is necessary, and thus generating the error because the "key encipherment" feature is required for an RSA public key, but in this case we are using an ECDHE_ECDSA public key. (The Java documentation is totally unhelpful here BTW.)

I fixed this in the latest build of Trireme, checked in to GitHub, and coming to a Maven snapshot repository soon. No release yet.

Fixing this in the Apigee Cloud will require us to adopt the latest build of Trireme, which will take us some more time. Apigee Support can help escalate this and make it happen more quickly.

Finally, you can work around this by passing the option "rejectUnauthorized: false" when creating a TLS connection or an HTTPS request in Node. This disables all certificate validation, so it is not a good production solution, but it does allow the connection to be made. I'm not sure how to get request to pass this down, however -- that may take more research.

https://nodejs.org/api/https.html#https_https_request_options_callback

https://nodejs.org/api/tls.html#tls_tls_connect_options_callback

Thanks @greg@apigee.com for confirming.

Not applicable

Nice! That makes sense. I remember running into this issue in the past because the TLS cert was expired or self-signed. I ended up leveraging rejectUnauthorized option like this:

req.pipe(request.post({url : config.url + '/authorization',rejectUnauthorized : false})).pipe(res);

For FB Node.js SDK, I guess it would be something like this based on the documentation:

var FB = require('fb');
FB.options({timeout: 1, accessToken: 'access_token', 'rejectUnauthorized' : false});


FB.api('/me', function (res) {
    if(res && res.error) {
        if(res.error.code === 'ETIMEDOUT') {
            console.log('request timeout');
        }
        else {
            console.log('error', res.error);
        }
    }
    else {
        console.log(res);
    }
});

And yes, this workaround was used on a development environment only.