When using OpenSSL, server certificates are verified automatically. By using Sock.SSL.VerifyCert := True;
, a verification error will lead to an exception. However, OpenSSL does not automatically verify the hostname in the certificate that is presented by the server. This is a security risk. If a server presents any non-expired certificate of a different host, this will be accepted in the current setup.
To have OpenSSL verify the hostname in the certificate, which IMHO is essential, the function SSL_set1_host
must be used (https://www.openssl.org/docs/man3.0/man3/SSL_set1_host.html). After adding this function to the Synapse code, certificate verification work correctly.
Please see the patches below to correct the code for the ssl_openssl, ssl_openssl11 and ssl_openssl3 variants. Many thanks in advance for correcting this asap, since the current code has an important security risk.
program project1;
uses httpsend, ssl_openssl3;
const URLs: array[0..5] of string = (
'https://badssl.com', // should work
'https://wrong.host.badssl.com', // should be rejected
'https://expired.badssl.com', // should be rejected
'https://self-signed.badssl.com', // should be rejected
'https://untrusted-root.badssl.com', // should be rejected
'https://revoked.badssl.com' // should be rejected
);
var
URL: string;
HTTP: THTTPSend;
begin
HTTP := THTTPSend.Create;
try
HTTP.Sock.SSL.VerifyCert := True;
HTTP.Sock.SSL.CertCAFile := 'ca-bundle.crt';
for URL in URLs do
begin
if HTTP.HTTPMethod('GET', URL) then
WriteLn('Success: ', URL)
else
WriteLn('Failure: ', URL, '; verify result: ', HTTP.Sock.SSL.GetVerifyCert);
end;
finally
HTTP.Free;
end;
end.
$ ./project1
Success: https://badssl.com
Success: https://wrong.host.badssl.com
Failure: https://expired.badssl.com; verify result: 10
Failure: https://self-signed.badssl.com; verify result: 18
Failure: https://untrusted-root.badssl.com; verify result: 19
Failure: https://revoked.badssl.com; verify result: 10
This output shows that the last four URLs are correctly rejected, but that wrong.host.badssl.com is incorrectly not rejected.
$ ./project1
Success: https://badssl.com
Failure: https://wrong.host.badssl.com; verify result: 62
Failure: https://expired.badssl.com; verify result: 10
Failure: https://self-signed.badssl.com; verify result: 18
Failure: https://untrusted-root.badssl.com; verify result: 19
Failure: https://revoked.badssl.com; verify result: 10
This is the correct output and the verify result is correctly 62.
(See OpenSSL source, which says: # define X509_V_ERR_HOSTNAME_MISMATCH 62)
See the attached patch files to repair the bug.
Thank you, fixed now!