Jump to content

jaenicke

Members
  • Content Count

    26
  • Joined

  • Last visited

  • Days Won

    1

Posts posted by jaenicke


  1. Hello,

     

    in Delphi 10.4 and Delphi 11 there is a problem with the taskbar. If you use the CustomTitleBar and maximize the window, the taskbar does not show up if it is set as automatically hidden. This applies to own programs as well as to the Delphi IDE.

     

    Since this has been fixed with Delphi 12, I no longer need to create a bug entry and there was already one for the Delphi IDE, in which I wrote that it works with Delphi 12.

     

    My problem now is that I have no idea what change in the VCL did the fix. I already searched, but have not found anything suitable. I have transferred the Vcl.TitleBarCtrls unit completely as a test, but that was not successful. Does anyone have any idea where the cause of the problem could lie, so that I can transfer the fix to Delphi 10.4?

     

    Many thanks to all readers!

    Sebastian


  2. On 11/5/2022 at 1:20 AM, klaus49 said:

    Unfortunately, I'm really stuck to Delphi 6 PE. I'm implementing a (huge) support DLL for another language, and all the stuff is writte, in Delphi 6 PE.

    What about using a second DLL? You could write this new DLL with Delphi Community Edition, where you can use newer components. Then you can load this new DLL by your old DLL and just redirect the calls to the new DLL. This way you do not have to upgrade your existing code, but you can use WebView4Delphi though.

    • Like 1

  3. Thank you! I didn't pay attention to this call as I do not make many calls, so speed does not matter. But of course I'll use this now that I am aware of it.

     

    There the error handling works correctly, though I would prefer not to get an exception, as I can configure it when calling the Get method. LibeayLoad always returns true instead. But it is not important as this is called only once.

     

    Thank you for your help!


  4. I first used interfaces via exported DLL functions. This was better than using many individual DLL functions, but still not very flexible.

     

    So I thought about how to implement the whole thing in a more general way. The result is this project.

     

    With AppCentral you can register interfaces in the host application or a DLL and get them in the host application or another DLL. The DLL can thereby also be written in C#, which is very practical, because you can connect various .NET libraries very well with Delphi.

     

    Example:
    Register an interface in Delphi

    
    type
      IAppDialogs = interface
      ['{EA3B37D8-5603-42A9-AC5D-5AC9C70E165C}']
        procedure ShowMessage(const AMessage: WideString); safecall;
      end;
    
      TAppDialogs = class(TInterfacedObject, IAppDialogs)
       public
         procedure ShowMessage(const AMessage: WideString); safecall;
       end;
    
    implementation
    
    { TAppDialogs }
    
    procedure TAppDialogs.ShowMessage(const AMessage: WideString);
    begin
      Vcl.Dialogs.ShowMessage(AMessage);
    end;
    
    initialization
      TAppCentral.Reg<IAppDialogs>(TAppDialogs.Create);
    
    finalization
      TAppCentral.Unreg<IAppDialogs>;

    Fetch the interface in the host application or a DLL

      TAppCentral.Get<IAppDialogs>.ShowMessage('This is a message!');
      // fetch directly, an exception will occur, if the interface is not registered yet

    Or in C#

    if (AppCentral.TryGet<IAppDialogs>(out IAppDialogs Dialogs))
    {
      Dialogs.ShowMessage("Message from DLL: C# DLL registered!");
    } 

    The project can be downloaded here:
    https://github.com/jaenicke/appcentral

    Demo applications are included in source and in compiled form.

     

    I'll add a quick start manual soon.

    • Like 5

  5. I only wanted to make an SSL call, so I don't think this is a very unusual call. A small example is:

    uses
      OverbyteIcsHttpProt, OverbyteIcsLogger, OverbyteIcsWSocket;
    
    procedure Test;
    var
      SslHttpCli: TSslHttpCli;
    begin
      SslHttpCli := TSslHttpCli.Create(nil);
      try
        SslHttpCli.SslContext := TSslContext.Create(SslHttpCli);
        SslHttpCli.URL := 'https://www.example.com';
        SslHttpCli.IcsLogger := TIcsLogger.Create(SslHttpCli);
        SslHttpCli.IcsLogger.LogOptions := [loSslInfo];
        SslHttpCli.Get;
      finally
        SslHttpCli.Free;
      end;
    end;

    The access violation happens, when Get is called.

     

    Of course not all calls can be checked, but I would recommend to do it in IcsX509VerifyErrorToStr, because it is used inside the error handling. You could do it this way:

    function IcsX509VerifyErrorToStr(ErrCode: Integer): String;
    begin
    {$IFNDEF OPENSSL_USE_RESOURCE_STRINGS}
      if Assigned(X509_verify_cert_error_string) then
        Result := String(AnsiString(X509_verify_cert_error_string(ErrCode)))
      else
    {$ENDIF}
        case ErrCode of
            X509_V_OK :
                Result := sX509_V_OK;
            X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
                Result := sX509_V_ERR_UNABLE_TO_GET_ISSUER_CERT;
            X509_V_ERR_UNABLE_TO_GET_CRL:
                Result := sX509_V_ERR_UNABLE_TO_GET_CRL;
            X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
                Result := sX509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE;
            X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
                Result := sX509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE;
            X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
                Result := sX509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;
            X509_V_ERR_CERT_SIGNATURE_FAILURE:
                Result := sX509_V_ERR_CERT_SIGNATURE_FAILURE;
            X509_V_ERR_CRL_SIGNATURE_FAILURE:
                Result := sX509_V_ERR_CRL_SIGNATURE_FAILURE;
            X509_V_ERR_CERT_NOT_YET_VALID:
                Result := sX509_V_ERR_CERT_NOT_YET_VALID;
            X509_V_ERR_CRL_NOT_YET_VALID:
                Result := sX509_V_ERR_CRL_NOT_YET_VALID;
            X509_V_ERR_CERT_HAS_EXPIRED:
                Result := sX509_V_ERR_CERT_HAS_EXPIRED;
            X509_V_ERR_CRL_HAS_EXPIRED:
                Result := sX509_V_ERR_CRL_HAS_EXPIRED;
            X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
                Result := sX509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD;
            X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
                Result := sX509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD;
            X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
                Result := sX509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD;
            X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
                Result := sX509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD;
            X509_V_ERR_OUT_OF_MEM:
                Result := sX509_V_ERR_OUT_OF_MEM;
            X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
                Result := sX509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT;
            X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
                Result := sX509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
            X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
                Result := sX509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY;
            X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
                Result := sX509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE;
            X509_V_ERR_CERT_CHAIN_TOO_LONG:
                Result := sX509_V_ERR_CERT_CHAIN_TOO_LONG;
            X509_V_ERR_CERT_REVOKED:
                Result := sX509_V_ERR_CERT_REVOKED;
            X509_V_ERR_INVALID_CA:
                Result := sX509_V_ERR_INVALID_CA;
            X509_V_ERR_INVALID_NON_CA:
                Result := sX509_V_ERR_INVALID_NON_CA;
            X509_V_ERR_PATH_LENGTH_EXCEEDED:
                Result := sX509_V_ERR_PATH_LENGTH_EXCEEDED;
            X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED:
                Result := sX509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED;
            X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED:
                Result := sX509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED;
            X509_V_ERR_INVALID_PURPOSE:
                Result := sX509_V_ERR_INVALID_PURPOSE;
            X509_V_ERR_CERT_UNTRUSTED:
                Result := sX509_V_ERR_CERT_UNTRUSTED;
            X509_V_ERR_CERT_REJECTED:
                Result := sX509_V_ERR_CERT_REJECTED;
            X509_V_ERR_APPLICATION_VERIFICATION:
                Result := sX509_V_ERR_APPLICATION_VERIFICATION;
            X509_V_ERR_SUBJECT_ISSUER_MISMATCH:
                Result := sX509_V_ERR_SUBJECT_ISSUER_MISMATCH;
            X509_V_ERR_AKID_SKID_MISMATCH:
                Result := sX509_V_ERR_AKID_SKID_MISMATCH;
            X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH:
                Result := sX509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
            X509_V_ERR_KEYUSAGE_NO_CERTSIGN:
                Result := sX509_V_ERR_KEYUSAGE_NO_CERTSIGN;
            X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
                Result := sX509_V_ERR_UNABLE_TO_GET_CRL_ISSUER;
            X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION:
                Result := sX509_V_ERR_UNHANDLED_CRITICAL_EXTENSION;
            X509_V_ERR_KEYUSAGE_NO_CRL_SIGN:
                Result := sX509_V_ERR_KEYUSAGE_NO_CRL_SIGN;
            X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE:
                Result := sX509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE;
            X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION:
                Result := sX509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION;
            X509_V_ERR_INVALID_EXTENSION:
                Result := sX509_V_ERR_INVALID_EXTENSION;
            X509_V_ERR_INVALID_POLICY_EXTENSION:
                Result := sX509_V_ERR_INVALID_POLICY_EXTENSION;
            X509_V_ERR_NO_EXPLICIT_POLICY:
                Result := sX509_V_ERR_NO_EXPLICIT_POLICY;
         { V8.39 lots more }
            X509_V_ERR_UNNESTED_RESOURCE:
                Result := sX509_V_ERR_UNNESTED_RESOURCE;
    
        else
            Result := sX509_V_ERR_NUMBER + IntToStr(ErrCode);
        end;
    end;

    Of course the resource strings have to be available as well. This way the error handling works correctly, if the DLL is not loaded (if it is neccessary, I don't know, whether any of those errors can occur then) and the correct error is displayed / logged.


  6. I had activated loSslInfo as LogOption. Then I got an access violation on another machine. The problem is:

    - TCustomSslWSocket.StartSslHandshake calls FSslContext.InitContext

    - An exception is raised, because libcrypto-1_1.dll is missing

    - This exception is handled in TCustomSslWSocket.StartSslHandshake, but inside the except block TriggerSslHandshakeDone is called. This would be no problem, if IcsX509VerifyErrorToStr would not be called there for logging purposes. In this function X509_verify_cert_error_string is used, which is nil, because the library is missing.

     

    I think this is a bug. Am I right?

     

    Thank you

     


  7. 10 minutes ago, gkobler said:

    Marco Cantu has written a blog where exactly this topic was discussed.

     

    https://blog.marcocantu.com/blog/2022-december-suggestions-help-delphi-compiler.html

    Das hatte ich tatsächlich nicht gelesen. Allerdings ist es schon ein Unterschied, ob es "nur" langsamer ist (beim Kompilieren in dem Fall) oder der LSP schlicht gar nicht mehr geht. Sprich der geht auf "Angehalten", arbeitet also auch nicht langsam weiter.


  8. Important hint regarding LSP

     

    Yesterday I noticed that with both Delphi 10.4 and Delphi 11, an invalid path reliably knocks out the LSP. (Yes, this is reported and goes its way).

     

    This invalid path can be at least in the system PATH, the library path and unfortunately already simply the search path. You can easily test this yourself by entering a non-existent path there and restart Delphi. Important: If you correct it, you may have to restart Windows. For some reason it is not always enough to restart Delphi and the DelphiLSP.exe (even if the system PATH is not changed). I haven't looked into that yet and it doesn't always happen.

    • Like 1
    • Thanks 2

  9. Important hint regarding LSP

     

    Yesterday I noticed that with both Delphi 10.4 and Delphi 11, an invalid path reliably knocks out the LSP. (Yes, this is reported and goes its way).

     

    This invalid path can be at least in the system PATH, the library path and unfortunately already simply the search path. You can easily test this yourself by entering a non-existent path there and restart Delphi. Important: If you correct it, you may have to restart Windows. For some reason it is not always enough to restart Delphi and the DelphiLSP.exe (even if the system PATH is not changed). I haven't looked into that yet and it doesn't always happen.

    • Thanks 1

  10. Hello,

     

    I tried to verify a certificate chain when accessing a simple https page (for example https://www.google.de). I tried ICS and Indy, but as both use OpenSSL I got the same error 20:

    Quote

    unable to get local issuer certificate

    I know what this means. OpenSSL does not access the local certificate store under Windows and thus cannot find the root certificate locally. I know, that I can provide a certificate manually, so it can be checked.

     

    But why is this neccessary? ICS has code to access the Windows certificate store and verifying the peer is an absolute routine task. I searched for hours to find such functionality, because I cannot believe, that this basic task needs so much manual work. I found OCSP functionality and other cool stuff (code to verify a cert chain in ICS, ...), but not what I needed (verification of the root cert in the chain as well using the system store).

     

    So my question is:

    Did I not find this functionality or is it really missing? I would have expected this to work just by activating peer verification in both frameworks (so the AOk parameter should be set to true, when the OnVerifyPeer events are called).

     

    Thank you in advance

    Kind regards

    Sebastian


  11. Thank you for your reply!

     

    I wrote test applications to append them here.

     

    When I was done, I tested a bit. And I found out, that this works:

    MemoryMappedFile.OpenExisting(mmfName);

    But if I use MemoryMappedFileRights.Read (which works in Delphi) or MemoryMappedFileRights.ReadWrite, it does not work anymore. I could use API Monitor to dig deeper, but for the moment I am glad that it works.

     

    I'll append the test projects soon.


  12. Hello,

     

    I used memory-mapped files a few times already, but it was always a Delphi application. I had no problems to create a MMF and open it with another Delphi application.

     

    Now I tried to connect to a MMF created by a Delphi application, but this time I tried it from a C# application. Unfortunately it does not find the MMF. If I prepend Global\, I need administrator privileges, but it does not work either.

     

    The code is straightforward:

    // Delphi side:
    CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, MMFSize, PChar(MMFName));
    
    // C# side:
    MemoryMappedFile.OpenExisting(mmfName, MemoryMappedFileRights.ReadWrite);

    I thought about using the API functions directly, but I did not try it yet. Is anything wrong with this code? Why doesn't it work?

     

    Thank you

    Sebastian


  13. 18 hours ago, Angus Robertson said:

    ICS has new classes TMsCertTools and TMsX509List to write and read SSL/TLS certificates to and from the Windows Certificate Store, including private keys.

    Thank you very much for your efforts. I'll take a look at it.

    18 hours ago, Angus Robertson said:

    keys and certificates are held in separate stores and the way they are linked together is badly documented and flaky

    I had already begun to doubt myself...

     

    In the meanwhile I found out, that the internal rest client of Delphi supports client based authentication... the problem is, that it can't be used, because there is no way to set the properties needed... So I made a quality entry:

    https://quality.embarcadero.com/browse/RSP-34451

    I redirected the virtual methods, so it works for me, but it is no good way, because everything is declared inside the implementation section. So having no RTTI I have to use the cpu view to find the VMT table and memory offsets to the addresses, which I have to redirect.

     

    The next problem is, that I can use the .NET class X509Certificate2 to open a certificate, for which I can get the public key afterwards by simply using GetPublicKey(). But if I try this using Delphi and your ICS classes or using other ways, I always have to provide a password, which I do not have (and do not need when using .NET). I tried an empty password as well, but it did not work. I do not know, whether this does not work or whether I made an error when loading the certificate data.


  14. I have one question left:

    Is it possible to use ICS to build a HTTP server where clients authenticate themselves using client certificates? I had a short look, but did not see, whether this is possible.

     

    On 7/27/2021 at 10:08 AM, Angus Robertson said:

    My reading suggests CryptAcquireCertificatePrivateKey is how you get the private key for a certificate you find in the store, but not tried it yet.

    I don't find a way using this function, but it already works, so it does not matter.

     

    On 7/27/2021 at 10:08 AM, Angus Robertson said:

    ICS has classes TX509Base and TX509List which allow certificates and bundles to be created, read and saved in various formats, there is sample OverbyteIcsPemtool that illustrates everything, and another OverbyteIcsX509CertsTst that acquires certificates from Let's Encrypt. including multi-domain wildcards.

    This is very interesting indeed as I don't need to call openssl.exe externally anymore with this functionality. 

     

    On 7/27/2021 at 10:08 AM, Angus Robertson said:

    Sorry, never used THTTPRIO so no idea what it does, but the ICS HTTP client supports client certificates.  You can use ICS synchronously, there are methods for that.

    THTTPRIO us used to use automatically generated client classes to communicate with a SOAP server. This way you do not need to build and analyze the XML contents manually. It would only be possible to change the engine behind by changing a few RTL units, so this is no option for general purpose.

     

    Thank you very much!


  15. 14 hours ago, Angus Robertson said:

    But since you have PFX and PEM files, not sure why you are using the Windows store.

    Because I did not find another way to apply the certificate including the private key to the request.

     

    Should CertCreateCertificateContext work with the contents of a .pfx file including the private key too? It did not work for me and I did not find anything except the hint to use PFXImportCertStore. Perhaps I did something wrong there too.

     

    14 hours ago, Angus Robertson said:

    PFXImportCertStore and PFXExportCertStoreEx seem to be preferred solution to convert to and from a PFX/PCKS12 blob containing a certificate, private key and intermediates.

    That would be interesting. At the moment I use openssl.exe externally to convert .pem + .key --> .pfx. But I found no way to do this using the API.

     

    If this conversion would not be necessary, it would be even better of course.

     

    14 hours ago, Angus Robertson said:

    I'm just adding import and export for certificates to and from the Windows store, for ICS. 

    Could ICS be used somehow with THTTPRIO for SOAP communication including client certificate authentication? If this would work, it would be really great. But as there is no official way to change the engine behind THTTPRIO, it would not be easy (if possible at all). And as ICS works asynchronously (what I like), the process flow is so different, that it won't match the way THTTPRIO works anyway. So I have little hope. 😉

     

    Thank you for your reply!

    Sebastian


  16. SOLVED

     

    Unfortunately I got no hint for an error when calling PFXImportCertStore, but the format of the parameter was wrong. This does not explain why the other way using the store did not work, but this would have been only a workaround anyway.

     

    What I can say at this point:
    The implementation of Embarcadero really is not good. There is already working code, but one cannot use it, because the functionality is completely unreachable.

    • Sad 1

  17. No idea? Nobody? :classic_huh:

     

    Well, in the meanwhile I checked the certicate files using "openssl -v -info" and they contain the private key as they should.

     

    I imported the .pfx file by using certlm.msc directly. The import works and the private key is visible there. The certificate is found by TWinHTTPClient correctly and I can select it in OnNeedClientCertificate.

     

    But nevertheless the result is the same:

    I get error 12185 (ERROR_WINHTTP_CLIENT_CERT_NO_PRIVATE_KEY).

     

    Is there anything that needs to be done in addition?


  18. Hello,

     

    I would like to use THTTPRIO / Soap and thus TWinHTTPClient with WinHttpSendRequest. Client side certificates are used for authentication. This all works in the old version under XE4 with Indy. There you can also load a certificate from a file etc. without installing it.

     

    Now I want to update this to Delphi 10.4.2. Unfortunately I found out that TWinHTTPClient is declared under implementation without Rtti information and uses hard-coded the MY store. So I see three possibilities: Load the certificate to MY store, bypass MY store and load a certificate directly as context, bypass MY store and load a certificate as store and fetch the context.

     

    So I have redirected the virtual method DoClientCertificateAccepted by VMT pointer, so that I can use WinHttpSetOption with WINHTTP_OPTION_CLIENT_CERT_CONTEXT. The fact that the reference to the request is not accessible from outside is no big deal either. No beautiful code, but at least it works and is easy to adapt for future versions of Delphi.

     

    The problem now is to get a certificate context. I get it loaded with CertCreateCertificateContext from a .pfx file. Unfortunately the link to the private key is missing. I haven't found a way to add it with e.g. CertSetCertificateContextProperty. Consequently, I get the error message that the private key is missing when I make the request.

     

    So I tried it with PFXImportCertStore. This way I can load the .pfx file too, can get the context, but unfortunately the private key seems not to be in it, at least after the call of CertSetCertificateContextProperty I get the value 80092004 when I call GetLastError. That means that the property was not found.

     

    Also a try with the Clever Internet Suite did not work.

     

    Long story short:
    I have a .p12 file as source, I have a .pem file with the certificate and a .key file with the private key, I have also already made a .pfx out of it. With this I would like to do the authentication via client certificate. Which way would you recommend and how can I do it?

     

    Thanks a lot
    Greetings
    Sebastian

×