grpc-dart
grpc-dart copied to clipboard
Hostname mismatch when using subjectAltName with ipv4 adress in ssl certificate.
I have the following error :
[ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: gRPC Error (code: 14, codeName: UNAVAILABLE, message: Error connecting:
HandshakeException: Handshake error in client (OS Error:
CERTIFICATE_VERIFY_FAILED: Hostname mismatch(../../third_party/boringssl/src/ssl/handshake.cc:393)), details: null, rawResponse: null, trailers: {})
when using an ipv4 adress to connect to a local server (written in dart) from a flutter windows app. I use a subject alternative name, to be able to pass this raw ipv4 adress.
I use the latest 3.0.2 version of grpc.
Repro steps
I have configured a server certificate and key, as well as client ones, with the following command :
openssl req -new -nodes -x509 -days 365 -keyout server.key -out server.crt -config config_ssl
(and also :)
openssl req -new -nodes -x509 -days 365 -keyout client.key -out client.crt -config config_ssl
Here is the config_ssl file :
[req]
default_bits = 4096
default_md = sha256
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
CN = <my ipv4adress>
[v3_req]
keyUsage = keyEncipherment, dataEncipherment, digitalSignature
extendedKeyUsage = serverAuth, clientAuth
subjectAltName = @alt_names
[alt_names]
IP.1 = <my-ipv4adress>
--> The error is above.
Details
Client
I use the following class that herits from ChannelCredentials for the Client :
class ClientCertificateChannelCredentials extends ChannelCredentials {
final List<int> _serverCert;
final List<int> _cert;
final List<int> _key;
final String ipAddress;
const ClientCertificateChannelCredentials(
this._serverCert,
this._cert,
this._key, {
required this.ipAddress,
}) : super.secure();
@override
SecurityContext get securityContext {
return SecurityContext()
..useCertificateChainBytes(_cert)
..usePrivateKeyBytes(_key)
..setTrustedCertificatesBytes(_serverCert)
..setAlpnProtocols(['grpc-exp', 'h2'], true);
}
@override
String? get authority {
print("getter returns $ipAddress");
return ipAddress;
}
}
This is used right there on the client :
channel = ClientChannel(
sslCertificates.ipAddress!,
port: 50051,
options: ChannelOptions(
credentials: ClientCertificateChannelCredentials(
sslCertificates.serverCertificateBytes!,
sslCertificates.clientCertificateBytes!,
sslCertificates.clientKeyBytes!,
ipAddress: sslCertificates.ipAddress!,
),
codecRegistry:
CodecRegistry(codecs: const [GzipCodec(), IdentityCodec()])),
);
client = SimpleClient(channel);
Server
class ServerTlsCredentialsWithClientCheck extends ServerTlsCredentials {
final List<int> certificateBytes;
final List<int> keyBytes;
final List<int> clientCertificatesBytes;
ServerTlsCredentialsWithClientCheck({
required this.clientCertificatesBytes,
required this.certificateBytes,
required this.keyBytes,
});
@override
SecurityContext get securityContext {
return SecurityContext()
..useCertificateChainBytes(certificateBytes)
..usePrivateKeyBytes(keyBytes)
..setTrustedCertificatesBytes(clientCertificatesBytes)
..setAlpnProtocols(['grpc-exp', 'h2'], true);
}
@override
bool validateClient(Socket socket) {
print(socket.address);
return super.validateClient(socket);
}
Btw, i don't know where this validateClient is called currently
Used here :
await server
.serve(
address: ipAddress,
//address: "localhost",
port: 50051,
security: ServerTlsCredentialsWithClientCheck(
clientCertificatesBytes: clientCertificates ?? [],
keyBytes: serverKeyBytes ?? [],
certificateBytes: serverCertificateBytes ?? [],
),
requestClientCertificate: true,
requireClientCertificate: true,
)
.onError((error, stackTrace) => print(error));
Any help would be much appreciated !