Fix SSL certificate check when hostname is an IP address

Closes https://github.com/dart-lang/sdk/pull/52118

GitOrigin-RevId: 7598354d2ad5baba2ed65177bdff521a637b5b65
Change-Id: I78246e423f6ee090030912576ab8202f0fa60509
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/296722
Reviewed-by: Brian Quinlan <bquinlan@google.com>
Commit-Queue: Brian Quinlan <bquinlan@google.com>
This commit is contained in:
Valentin Hăloiu 2023-04-25 16:06:12 +00:00 committed by Commit Queue
parent d440905d5a
commit db766b37cb
5 changed files with 51 additions and 2 deletions

View file

@ -13,6 +13,7 @@
#include "bin/lockers.h"
#include "bin/secure_socket_utils.h"
#include "bin/security_context.h"
#include "bin/socket_base.h"
#include "platform/syslog.h"
#include "platform/text_buffer.h"
@ -540,8 +541,16 @@ void SSLFilter::Connect(const char* hostname,
certificate_checking_parameters,
X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_TRUSTED_FIRST);
X509_VERIFY_PARAM_set_hostflags(certificate_checking_parameters, 0);
status = X509_VERIFY_PARAM_set1_host(certificate_checking_parameters,
hostname_, strlen(hostname_));
// Use different check depending on whether the hostname is an IP address
// or a DNS name.
if (SocketBase::IsValidAddress(hostname_)) {
status = X509_VERIFY_PARAM_set1_ip_asc(certificate_checking_parameters,
hostname_);
} else {
status = X509_VERIFY_PARAM_set1_host(certificate_checking_parameters,
hostname_, strlen(hostname_));
}
SecureSocketUtils::CheckStatusSSL(
status, "TlsException", "Set hostname for certificate checking", ssl_);
}

View file

@ -301,5 +301,19 @@ void FUNCTION_NAME(SocketBase_IsBindError)(Dart_NativeArguments args) {
Dart_SetBooleanReturnValue(args, is_bind_error ? true : false);
}
bool SocketBase::IsValidAddress(const char* address) {
ASSERT(address != nullptr);
RawAddr raw;
memset(&raw, 0, sizeof(raw));
int type = strchr(address, ':') == nullptr ? SocketAddress::TYPE_IPV4
: SocketAddress::TYPE_IPV6;
if (type == SocketAddress::TYPE_IPV4) {
raw.addr.sa_family = AF_INET;
} else {
raw.addr.sa_family = AF_INET6;
}
return SocketBase::ParseAddress(type, address, &raw);
}
} // namespace bin
} // namespace dart

View file

@ -274,6 +274,8 @@ class SocketBase : public AllStatic {
static bool ParseAddress(int type, const char* address, RawAddr* addr);
static bool IsValidAddress(const char* address);
// Convert address from byte representation to human readable string.
static bool RawAddrToString(RawAddr* addr, char* str);
static bool FormatNumericAddress(const RawAddr& addr, char* address, int len);

View file

@ -110,6 +110,7 @@ Future testClientCertificate(
main() async {
asyncStart();
// Test client certificate when host is a DNS name
HOST = (await InternetAddress.lookup("localhost")).first;
await testClientCertificate(
required: false, sendCert: true, certType: 'pem', password: 'dartdart');
@ -128,5 +129,16 @@ main() async {
required: false, sendCert: false, certType: 'p12', password: 'dartdart');
await testClientCertificate(
required: true, sendCert: false, certType: 'p12', password: 'dartdart');
// Test client certificate when host is an IP address
HOST = InternetAddress.loopbackIPv4;
await testClientCertificate(
required: false, sendCert: true, certType: 'pem', password: 'dartdart');
await testClientCertificate(
required: true, sendCert: true, certType: 'pem', password: 'dartdart');
await testClientCertificate(
required: false, sendCert: false, certType: 'pem', password: 'dartdart');
await testClientCertificate(
required: true, sendCert: false, certType: 'pem', password: 'dartdart');
asyncEnd();
}

View file

@ -110,6 +110,7 @@ Future testClientCertificate(
main() async {
asyncStart();
// Test client certificate when host is a DNS name
HOST = (await InternetAddress.lookup("localhost")).first;
await testClientCertificate(
required: false, sendCert: true, certType: 'pem', password: 'dartdart');
@ -128,5 +129,16 @@ main() async {
required: false, sendCert: false, certType: 'p12', password: 'dartdart');
await testClientCertificate(
required: true, sendCert: false, certType: 'p12', password: 'dartdart');
// Test client certificate when host is an IP address
HOST = InternetAddress.loopbackIPv4;
await testClientCertificate(
required: false, sendCert: true, certType: 'pem', password: 'dartdart');
await testClientCertificate(
required: true, sendCert: true, certType: 'pem', password: 'dartdart');
await testClientCertificate(
required: false, sendCert: false, certType: 'pem', password: 'dartdart');
await testClientCertificate(
required: true, sendCert: false, certType: 'pem', password: 'dartdart');
asyncEnd();
}