DelphiGuy
DelphiGuy

Reputation: 231

Delphi TNetHTTPRequest/TNetHTTPClient Works on Win 10, but not Win 7

New details added beneath the source code.

Having an issue is Delphi where the Internet code works on Win 10, but not on Win 7. I’m trying to hook up a small project to haveibeenpwned.com (HIBP). Win 7 returns “Error getting Server Certificate.”

To try to fix the Win 7 issue, I added an OnValidateServerCertificate to both the TNetHTTPRequest and TNetHTTPClient. In both Win 10 and Win 7, OnValidateServerCertificate does not seem to be called.

I have tested on 2 Win 10 computers and 2 Win 7 computers, same results. 1) Why does Win 7 return “Error getting Server Certificate? 2) Why doesn’t OnValidateServerCertificate get called on Win 10 or Win 7?

Thanks for any help!

unit MainUnt;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, 
System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.Net.URLClient, 
System.Net.HttpClientComponent,
  System.Net.HttpClient;

type
  TForm9 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    function HIBPGetRangeResults( const AFirst5CharHashStr: String;
                                  out ARangeResultsStr: String;
                                  out AErrStr: String ): Boolean; inline;
    procedure OnValidateServerCertificate( const Sender: TObject;
                                       const ARequest: TURLRequest;
                                       const Certificate: TCertificate;
                                       var Accepted: Boolean );
  end;

var
  Form9: TForm9;

implementation

{$R *.dfm}

//SHA1( Pa$$word ): 775440A2B268C2F58A9A61B10CC10125703B3015
procedure TForm9.Button1Click(Sender: TObject);
var
  TmpErrStr: String;
  TmpResultsStr: String;
begin
  //HIBP Range wants only the first 5 charactsers so search is anonymous.
  if HIBPGetRangeResults( '77544', TmpResultsStr, TmpErrStr ) then
    ShowMessage( TmpResultsStr )
  else
    ShowMessage( TmpErrStr );
end;

function TForm9.HIBPGetRangeResults( const AFirst5CharHashStr: String;
                                     out ARangeResultsStr, AErrStr: String): 
Boolean;
const
  //GET https://api.pwnedpasswords.com/range/{first 5 hash chars}
  //I don't know of another site at this point that works on Win 10, but 
fails on Win 7.
  kServiceNameStr = 'https://api.pwnedpasswords.com/range/';
var
  TmpNetHTTPRequest: TNetHTTPRequest;
  TmpNetHTTPClient: TNetHTTPClient;
  TmpIHTTPResponse: IHTTPResponse;
begin
  Result := False;
  try
    TmpNetHTTPRequest := TNetHTTPRequest.Create( Nil );
    TmpNetHTTPClient := TNetHTTPClient.Create( Nil );
    try
      TmpNetHTTPClient.OnValidateServerCertificate := 
OnValidateServerCertificate;
      TmpNetHTTPClient.ConnectionTimeout := 3000;
      TmpNetHTTPClient.ResponseTimeout := 3000;
      TmpNetHTTPClient.UserAgent := 'Testing'; //HIBP wants User Agent 
filled.

      TmpNetHTTPRequest.OnValidateServerCertificate := 
OnValidateServerCertificate;
      TmpNetHTTPRequest.ConnectionTimeout := 3000;
      TmpNetHTTPRequest.Client := TmpNetHTTPClient;
      TmpNetHTTPRequest.URL := kServiceNameStr + AFirst5CharHashStr;

      TmpIHTTPResponse := TmpNetHTTPRequest.Execute;
      if TmpIHTTPResponse.StatusCode=200 then
      begin
        ARangeResultsStr := TmpIHTTPResponse.ContentAsString;
        Result := True;
      end
      else
      begin
        AErrStr := 'Result:' + TmpIHTTPResponse.StatusText;
      end;
    finally
      FreeAndNil( TmpNetHTTPClient );
      FreeAndNil( TmpNetHTTPRequest );
    end;
  except on E: Exception do
    AErrStr := E.Message;
  end;
end;

procedure TForm9.OnValidateServerCertificate( const Sender: TObject;
                                              const ARequest: TURLRequest;
                                              const Certificate: 
TCertificate;
                                              var Accepted: Boolean );
begin
  //Just to know it's been called at all.
  //Not called in Win 10 or Win 7.
  Beep;
end;

end.

The link https://api.pwnedpasswords.com/range/55555 (sample first 5 char hash) was returning a certificate error in IE. I added TLS 1.1 and 1.2 in the Win 7 Internet Options, Advanced. This allowed the browser to work.

Still the program didn't work. So I grepped the Delphi Source (Berlin) "Error getting Server Certificate" which led to "SNetHttpGetServerCertificate". In System.Net.HttpClient:

procedure THTTPClient.DoValidateServerCertificate(LRequest: THTTPRequest);

...

LServerCertificate := DoGetSSLCertificateFromServer(LRequest);
if LServerCertificate.Expiry = 0 then
  raise 
ENetHTTPCertificateException.CreateRes(@SNetHttpGetServerCertificate);

That seems to be the only spot this exception can be raised from. Unfortunately, putting a break point there (even with Debug DCUs on) was never hit.

There is a ServerCertificateInvalid possibility within TWinHTTPClient.DoExecuteRequest that I pass while stepping through. I can't tell from my Win 10 machine if this is being triggered on Win 7.

Also, the domain I'm calling seems to be using a very modern SSL config: https://www.ssllabs.com/ssltest/analyze.html?d=api.pwnedpasswords.com&s=104.17.70.67.

Perhaps something is incompatible with this config, Delphi (Berlin) and Win 7?

Thanks for any help!

Upvotes: 5

Views: 10516

Answers (3)

2borG
2borG

Reputation: 88

Actually found the solution, not related to Delphi.

From MS:

Applications and services that are written by using WinHTTP for Secure Sockets Layer (SSL) connections that use the WINHTTP_OPTION_SECURE_PROTOCOLS flag can't use TLS 1.1 or TLS 1.2 protocols. This is because the definition of this flag doesn't include these applications and services.

This update adds support for DefaultSecureProtocols registry entry that allows the system administrator to specify which SSL protocols should be used when the WINHTTP_OPTION_SECURE_PROTOCOLS flag is used.

This can allow certain applications that were built to use the WinHTTP default flag to be able to leverage the newer TLS 1.2 or TLS 1.1 protocols natively without any need for updates to the application.

Fix:

https://support.microsoft.com/en-au/help/3140245/

Upvotes: 7

2borG
2borG

Reputation: 88

Same problem here acessing https://www.geocaching.com/account/login Working in windows 10 without a problem, but getting "Server Certificate Invalid or not Present" on TNetHTTPClient.Get.

Setting Accepted := True; on OnValidateServerCertificate will give "Error getting Server Certificate".

What workaround did you use?

Upvotes: 0

DelphiGuy
DelphiGuy

Reputation: 231

Couldn't get the haveibeenpwned.com (HIBP) certificate to work on my 3 Win 7 test computers. One VM, 2 physical.

Downloaded HIBP data and imported some of it as a test to Amazon S3 with each 5 character prefix as an S3 public object.

Now the same code as above works with only the url changed.

I still don't know why the "Error getting Server Certificate" kept appearing on Win 7, but found an acceptable work around.

Thanks to all who viewed this!

Upvotes: 0

Related Questions