grpc / grpc/grpc-node

How to detect invalid tls certificate early and abort failed connection attempt

Open
#733 4 comments 0 reactions 0 assignees View on GitHub
package: @grpc/grpc-js
Dominant language
TypeScript
Stars
4.8k
Forks
716
Avg merge
2d 3h
Merged PRs (30d)
10

Description

### Problem description

When attempting to establish a gRPC connection using an invalid tls certificate (one in which the IP address or hostname that I'm trying to connect to is not included in the certificate that I'm trying to connect with) I would like to be able to detect the fact that the certificate is invalid and present an appropriate message to our users.

Currently, what happens is that the connection attempt will keep trying until the deadline has passed (20 seconds in our case), at which point a rather generic "Unable to connect before the deadline" error will be thrown. This gives the user no indication that the problem is with the certificate.

My question is:

1. Is there a way to make grpc-js throw an error early if the certificate is found to be invalid rather than trying over and over again until the deadline is exceeded?

2. And, is there a way to have grpc-js throw an error that is specific to the reason for the failure (invalid cert), rather than a generic failure error due to the deadline being exceeded?

### Reproduction steps

```js
import { credentials } from '@grpc/grpc-js'

const packageDefinition = await load('/path/to/service.proto')
const MyService = loadPackageDefinition(packageDefinition)

const host = '1.2.3.4:1234'
const invalidCert = await readFile(certPath)

const sslCreds = await credentials.createSsl(invalidCert)

const service = new MyService(host, sslCreds)
```

### Environment
- OS name, version and architecture: [e.g. Linux Ubuntu 18.04 amd64]: Mac
- Node version [e.g. 8.10.0]: v11.6.0
- Node installation method [e.g. nvm]: core
- If applicable, compiler version [e.g. clang 3.8.0-2ubuntu4]
- Package name and version [e.g. gRPC@1.12.0]: @grpc/grpc-js@0.3.5

### Additional context

Looking through the code, I found `checkServerIdentity` and thought that perhaps I could use this in order to do some verification of my own. However this doesn't seem to work for my purposes. For example, with this:

```js
import { credentials } from '@grpc/grpc-js'

const packageDefinition = await load('/path/to/service.proto')
const MyService = loadPackageDefinition(packageDefinition)

const host = '1.2.3.4:1234'
const invalidCert = await readFile(certPath)

const sslCreds = await credentials.createSsl(invalidCert, null, null, {
checkServerIdentity(host, cert, rest) {
console.log('host', host)
console.log('cert', cert)
return true
}
})

const service = new MyService(host, sslCreds)
```

In this case, my custom `checkServerIdentity` only gets called if if I try to connect with a valid certificate. If I use an invalid certificate, grpc-js own validation fails and it never gets as far as calling my own function. An even so, causing a rejection here (by returning `true`) only causes grpc to try over and over again until the deadline has exceeded - it does not abort the connection attempt.

I have also tried this with the native grpc implementation, but the result is the same. There, when I run with `GRPC_TRACE=all GRPC_VERBOSITY=DEBUG` set I can see that it's trying the connection over and over again with the invalid cert. I can even see that it's getting TLS errors when trying to use the cert, but I have been unable to figure out how to hook into this and make it abort early. There is no point in trying the connection over and over again with an invalid certificate.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.