grpc: [Node.js] Handshake failed with fatal error SSL_ERROR_SSL: BAD_ECC_CERT

Hello, I am trying to connect from node.js script to external grpc API using TLS with self signed cert (please see below) but during the handshake grpc terminates with following error:

E0527 09:49:28.689000000  4712 ssl_transport_security.c:945] Handshake failed with fatal error SSL_ERROR_SSL: error:1000006b:SSL routines:OPENSSL_internal:BA
D_ECC_CERT.
E0527 09:49:28.689000000  4712 handshake.c:241] Handshake failed with error TSI_PROTOCOL_FAILURE
E0527 09:49:28.689000000  4712 secure_channel_create.c:99] Secure handshake failed with error 1.
{ [Error] code: 14, metadata: Metadata { _internal_repr: {} } }

I am running Node.js (v.4.4.5 LTS) under win 7 (x64bit) with GRPC package (v. 0.14.1) installed via npm install grpc --save.

The script I am running is this:

var fs = require('fs');
var path = require('path');
var os = require('os');

process.env['GRPC_SSL_CIPHER_SUITES'] = 'HIGH+ECDSA';

var grpc = require('grpc');
var protoDescriptor = grpc.load('./api.proto');
var walletrpc = protoDescriptor.walletrpc;

var cert = fs.readFileSync('rpc.cert');
var creds = grpc.credentials.createSsl(cert);
var client = new walletrpc.WalletService('127.0.0.1:9110', creds);

var request = {
    account_number: 0,
    required_confirmations: 1
};
client.balance(request, function(err, response) {
    if (err) {
        console.error(err);
    } else {
        console.log('Spendable balance:', response.spendable);
    }
})

Certificate file is standard certificate:

-----BEGIN CERTIFICATE----- MIICkzCCAfWgAwIBAgIRAMtVW1yCGKIrJBcbmqYVu3owCgYIKoZIzj0EAwQwPDEl MCMGA1UEChMcZGNyd2FsbGV0IGF1dG9nZW5lcmF0ZWQgY2VydDETMBEGA1UEAxMK bm9uYW1lMi1QQzAeFw0xNjA0MjUyMTIwMTJaFw0yNjA0MjQyMTIwMTJaMDwxJTAj BgNVBAoTHGRjcndhbGxldCBhdXRvZ2VuZXJhdGVkIGNlcnQxEzARBgNVBAMTCm5v bmFtZTItUEMwgZswEAYHKoZIzj0CAQYFK4EEACMDgYYABAASZVcgIuql7ho9aGv0 X0DuHVcAKBmBbegMi7fPbaXRNmIDFQ3XKaj/lbNGYXX5AyEhaTckZQn0KZip6onh qG2SFgEpy4uaUULC84m5axEX21X4c74moLHkbklYkRQWRRIBfVqfKPc0QUPUwn7r PQnmAUARq9Nndlh8EDTEGZATSU3gYKOBlDCBkTAOBgNVHQ8BAf8EBAMCAqQwDwYD VR0TAQH/BAUwAwEB/zBuBgNVHREEZzBlggpub25hbWUyLVBDgglsb2NhbGhvc3SH BH8AAAGHEAAAAAAAAAAAAAAAAAAAAAGHBMCoAWSHEP6AAAAAAAAArEkF3rly3muH BAoEE9KHEP6AAAAAAAAA/XXG85N81M+HBMCoOAEwCgYIKoZIzj0EAwQDgYsAMIGH AkIBX6FOBzDM0kUGIXNfNljng0T4aIk/xCHACdSa56iaqQxM25CmZSri2lT0rMIV WX7FcrQLYUN3GXMy4nmTGOwG2mgCQUhutDgUjTslkie+5QM9HGAtNKg09e9yGyQ0 NYR99j5FNVmNvvS3kRF33XncGvundj21SEKWo/ykYMpIWYW8F/fl -----END CERTIFICATE-----

Please help me with this error - where is the problem/how should I debug it ? Is it cert problem - GRPC problem ? Thank you very much in advance for any help!

About this issue

  • Original URL
  • State: open
  • Created 8 years ago
  • Comments: 33 (10 by maintainers)

Most upvoted comments

For the sake of documentation, the offending code is:

https://github.com/grpc/grpc/blob/7b63731b87ccdcc24b03e25f13a2bb91d0531b0f/src/core/tsi/ssl_transport_security.cc#L695

It appears this code was added to configure ECDH to use P-256, but it has the side effect of also restricting ECC certificate keys to that curve.

Certs using the P-256 curve are working fine.

I notice that the certificate you are using uses IP addresses as Subject Alternative Names. And the primary difference between the Linux and Windows versions of the gRPC library is that the Linux library uses OpenSSL and the Windows library uses BoringSSL. It may be that BoringSSL cannot handle that kind of certificate.

As an alternative to using machine-specific certificates for testing, you can use a regular certificate for a domain, and initialize the client with a couple of extra options. For example, you could use a self-signed certificate for example.com and change the client construction line to this:

var options = {
  'grpc.ssl_target_name_override' : 'example.com',
  'grpc.default_authority': 'example.com'
};
var client = new walletrpc.WalletService('127.0.0.1:9110', creds, options)

This will make the client validate the certificate it receives as though it came from example.com.

To add more detail to this issue, the same client and server code work fine on Linux, but the client is unable to connect when running on Windows.

Keys and certificates are being generated with this code: https://github.com/decred/dcrutil/blob/85fac3a15425f15408f1dcec28bfd4b18ea2f882/certgen.go#L25

There is also a standalone tool that can be used to generate the keypairs (can be useful for reproducing this issue with other servers). To install: go get -u github.com/decred/dcrd/cmd/gencerts.

This also happens on the Python library.

In any case, P384 curves are not supported. You have to use P256. Probably a BoringSSL issue.