ap2021
Members-
Content Count
38 -
Joined
-
Last visited
Everything posted by ap2021
-
I know that some parts of ICS compile for Linux and so I have tried using ICS SSL, but ran into issues: 1) Compile errors referring to somethingRCDATAsomething led me to remove all included resources, including all OpenSSL stuff - executables and bundles, etc. Now it compiles and links Ok. 2) The project is an Apache module and without ICS it works, but with the minimum SSL functionality that I need, it starts alright (so Apache is happy at this stage) and immediatly exits (at which stage Apache hangs and eventually errors out 1min or so later), without any errors at any stage anywhere in between. I'm using a RHEL clone - Oracle Linux, v. 9.2, which is recent, with whatever the latest Apache it ships with, Delphi Alexandria and WebBroker. The combination works, as I have another module working. Since I cannot debug into it, I rely on logs. I can see it ticking through nicely until Application.Run, then the immediatate next line, then the last line in the DPR and then some code used in one of my units finalization section, non-stop. WebModuleCreate is never called, but maybe it's only kicking in on actual client connections, so it probably means nothing. Apache logs nothing useful either. The last entry I can see is this: "[http2:debug] [pid 1002119:tid 1002119] mod_http2.c(112): AH03089: initializing post config dry run", which does not look like an error. I have exception handlers all around - nothing is logged from there. No SIG's are reported anywhere, apart from the very end, after the timeout triggers cleanup in Apache: Starting The Apache HTTP Server... AH01574: module session_module is already loaded, skipping AH01574: module wsgi_module is already loaded, skipping httpd.service: start operation timed out. Terminating. httpd.service: State 'stop-sigterm' timed out. Killing. httpd.service: Killing process 1002119 (httpd) with signal SIGKILL. httpd.service: Main process exited, code=killed, status=9/KILL httpd.service: Failed with result 'timeout'. systemd[1]: Failed to start The Apache HTTP Server. Anyone tried any of this before? Any tips or tricks, or hopefully solutions you can share?
-
Fair enough, still a shame to see a good advise go to waste...
-
Trying to send an email (through ICS), but getting it BASE64 encoded. The Content-Transfer-Encoding header on the message is set to just a single letter "b". Looks like the encoding is messed up somewhere, but it's all ICS vanilla code, all I do is call the SslSmtpCli object and have a callback to perform the steps. Also, I think it used to work for me before. Were there any breaking changes there recently? PS: Changing the DefaultEncoding to smtpEncQuotedPrintable, for instance, sets that header to "q" and the message contains some garbage.
-
Angus, Just wanted to add that fundamentally, sometimes you need to process actual text strings (ANSI or not) and sometimes binary data and it would be nice if this distinction was immediately obvious. It's a universal semantical headache, and C++ has the same problem, because there are just so many data types available and they may all look the same and essentially do the same thing. For example in OpenSSL, there are such function declarations: int EVP_DigestVerifyInit_ex(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const char *mdname, OSSL_LIB_CTX *libctx, const char *props, EVP_PKEY *pkey, const OSSL_PARAM params[]); Here, mdname is semantically a string. So it can be / actually is 0-terminated and with no size needed separately, hence pansichar is the correct type we should use in translated Pascal definitions. Unless we know for a fact that the target function expects and can handle Unicode text in UTF8, then we must use putf8char datatype in the tarnslated definitions, or it would cause problems, unless additionally typecast. But here: int EVP_DigestSignUpdate(EVP_MD_CTX *ctx, const void *data, size_t dsize); The data parameter is semantically binary data - they are trying to convery this by using the word "data", there's also a requirement to pass in the size separately and they are trying to use a different data type for it, not just "const char *" (which it could have been, interchangeably), but "const void *". Sometimes, in exactly same way, they may use "const unsigned char *" type instead, but that's because they are just as confused about it as we are in Delphi: __owur int EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, size_t siglen, const unsigned char *tbs, size_t tbslen); In fact they may have interchangeably used "const char *" for the same data in odd places, because apart from the semantics, it would achieve the same result and if the original developer was tired or lazy, the type used may not reflect its semantical significance. Besides, C++ has no special data type for binary data, so this issue has no silver bullet solution in C++. This confusion then spills over into all other languages and then you translate it in your code, without regard to semantics, as: EVP_DigestVerify : function(ctx: PEVP_MD_CTX; sigret: PAnsiChar; siglen: size_t; tbsret: PAnsiChar; tbslen: size_t): Integer; cdecl = Nil; { V8.52, V8.64 corrected declaration } using PAnsiChar type. This may have been acceptable in Delphi 1 days, but today we have a better data type we should use instead: TBytes. You do not want sematics to be lost in translation, although the original semantics may need to be deduced first, because in C++ it may not be very clear. These functions should be declared in Delphi with TBytes type instead, i.e.: EVP_DigestVerify : function(ctx: PEVP_MD_CTX; sigret: TBytes; siglen: size_t; tbsret: TBytes; tbslen: size_t): Integer; cdecl = Nil; { A future version, properly corrected declaration } or EVP_DigestVerify : function(ctx: PEVP_MD_CTX; const sigret: TBytes; siglen: size_t; const tbsret: TBytes; tbslen: size_t): Integer; cdecl = Nil; { A future version, properly corrected declaration } Which is essentially the same for the operation of the function, but is semantically much clearer and 1) allows Delphi to enforce the type and avoid any internal conversions, 2) will directly accept TBytes parameters without resorting to very frequent PAnsiChar() typecasts and 3) will keep it much clearer to the user/coder. For instance, this will allow you to avoid weird conversions like these: function IcsAsymVerifyDigest(const Data, OldDigest: AnsiString; PublicKey: PEVP_PKEY; HashDigest: TEvpDigest = Digest_sha256): Boolean; begin Result := IcsAsymVerifyDigestTB(IcsStringAToTBytes(Data), IcsStringAToTBytes(OldDigest), PublicKey, HashDigest); end; And will allow you to get rid of AnsiString and AnsiChar parameters, at least the majority of them. With some thought before changes and some testing after, it would really clean up this mess. It cannot be blindly applied to any such translated datatype, each function will need to be looked at separately to figure out the underlying meaning of the type used. But again, perhaps it does not have to be applied to all declarations at once, you can start with a handful of these functions, either picking the ones that you use, or care about or those that may seem easier and then roll it out to others at will. Also, for Delphi, PAnsiChar literally refers to "0-terminated strings", which causes it to drop parts of data after the first #0 it encounters, when it's doing internal conversions, those we do not see and do not expect, therefore introducing hard to troubleshoot bugs. Does this make sense? Do you agree?
-
I guess an even easier fix would have been to define Smtp DefEncArray with pansichar in the first place. Angus, please add it to your list. I can confirm that Olli73's solution works.
-
Many thanks, that was indeed the solution! Wunderbar!
-
Just set the DefaultEncoding property to smtpEncBase64. The text is fine, it just gets BASE64-encoded and then never decoded by the mail client. TSslSmtpCli works with normal UTF16 strings and theres very little stuff going on outside of it, so there are no character conversions that I can see and none that I do, all text I tested so far was just plain English.
-
Oct 13, 2024 You should get rid of those ansistrings in all callable routines and do the conversions behind the scenes if you must.
-
Interestingly enough, this "fix" broke it for me under Windows. The fix for which, was to just use TB version. Ansistrings are unpredictable now, Delphi supports them reluctantly and there are probably unwarranted conversions going on under the hood, somewhere, using pansichar's.
-
I have 2 similar projects, looking at them side by side, both have a TDataModule-descendant form, but ICS control lists offered are very different. One did not have VCL assigned, I did that manually in .DPROJ and restarted IDE. Both have the same Win32 platform. Switching to Win64 greys out some entries, keeping the same long list in the good project, but in the bad project, there are only 4 controls offered under ICS SSL (and one is greys out in x64). Trying to copy the controls from form to form produces an error: Search path is the same in both. Can this be somehow controlled?
-
Does ICS offer anything to create ISAPI modules or filters for IIS? MS warns that "HTTP.sys isn't compatible with the ASP.NET Core Module and can't be used with IIS or IIS Express.", therefore there may be compatibility issues there. In my scenario, I also intend to run this on a Plesk-managed server, which offers full remote management for IIS, as well as setting up free Let's Encrypt certificate and automatically renewing it every 3 months - this latter is my main reason to use this IIS setup and not http.sys. If I can reproduce it with ICS components, I will certainly try.
-
It's just convenient sometimes, that's all. PS: Manually removing multi-platform garbage from DPROJ files in Notepad has now become almost mandatory. I started doing that because a) all that did not make any sense there and b) it was wasting space, but now it's easy to see how that garbage is actually causing problems.
-
So am I, pirated it on floppies too. And you are just being rude. I have not only described this issue perfectly, I have also provided 3 easy reproducible test cases, 2 of which exhibit this issue and 1 does not. Anyway, it boiled down to the multi-platform garbage DataSnap wizard adds to the DPROJ. And _manually_ removing it, fixes this issue: after that, all ICS components become available. So while yes, it's a Delphi problem, you should document it on your side as well: without this knowledge, ICS is not easily usable in DataSnap or DLL projects. And it is a manual DPROJ editing task, there's no GUI for that in IDE. I should probably advertise a class on how to do that 😉
-
Angus, my test case is to create a new DLL project, add Data Module and try placing any ICS controls on it - very few show as available. There's something about Libraries that ICS does not like, it would seem. Is this what you would expect? Or anything you can change? The same happens with projects created by DataSnap WebBroker wizard (targeting Windows/IIS ISAPI). But remarkably, a Windows/ISAPI projects created by IntraWeb wizard do not have this issue: I can see and use all ICS components on any of the 3 modules/forms it creates. So, perhaps it's not the fact that it's a Library? It's got to be something else.
-
Francois, thanks, but you cannot modify this setting from the IDE, it's a Delphi thing, hence half the time you have to manually edit .DPROJ. Sure, it all works, and if I were to redo it all from scratch, I'm sure it'll work, I must still be missing some tiny difference in some file there. I can manually add these components to PAS/DFM and it builds, but it would not display the controls on this one form for me and would pop up warnings along the way. I wish they finally fixed this DPROJ mess. This question probably does not belong in this forum, it has nothing to do with ICS and there's probably nothing you couyld do from your side, sorry for that.
-
Another very annoying thing under Linux is that ansistring's look Chinese in the debugger: There's no telling what the values are. And typecasting when inspecting values does not work, it would say "ansistring not defined", i.e.: My next hurdle is that it would not load PEM cert: it just cryptically fails. If I were to add "string" vars here, do the assignments, re-run and check the values of strings, then it does show the values. There's of course nothing you can do about that, it's a Delphi bug. But I might write another similar function to use TBytes instead - that would at least show something... Its not permissions, as I ran it as "root" and it was my file to start with. But as it did the validation Ok now, I also know that all shared libraries are fine. Go figure ;-( Ok, never mind, I did figure, no issues now, it loads and everything 😉
-
Using IcsBase64UrlDecode was my mistake, IcsBase64UrlDecodeA actually worked. With IcsBase64UrlDecode, it was relying on implicit conversions, I guess, and while it worked under Windows, it wasn't working under Linux. Similarly with TB versions, it had to be TBA.
-
Sure. I haven't done a lot of testing and do not know which exact line has caused it for me. Plus, the fact there are a number of IcsBase64UrlDecodeXXX functions there, which should have seemingly all worked, i.e.: it's somewhat confusing. But I do know that TNetEncoding.Base64URL.DecodeStringToBytes, which I am now using, is the solution. You may not be able to use TNetEncoding.Base64URL.DecodeStringToBytes, though, because it may not exist in older versions of Delphi, just not exactly sure how far back you have to support it. If I do do more testing and figure out a single-line fix for this in ICS, I will share it here.
-
IcsBase64UrlDecodeTB  has the same problem, because the fault is in Base64Decode. So, you should be able to reproduce it by just calling Base64Decode, try: 3I2c2shPwo4E7Y9Npyp7A5s4bkw9u3BV0sNsn4Ph2WAZFXduaTy8ZirXa8cQF2_Riwckxcqf2DYmdUKGDb1FCBESW34oV2V5PopqS2llIfwU6gwrbWycQuai7FUG-UZWfud64ZRqbk8oyyYD7gHfijUiZ-nOHd3ozzDS0NNnH6TKCHiwKu-ocqzT7pDUMr3ozu2Gv0Gb4txtQk4m2QbNn4uNmYrSjgKzNH3HYWQgBYAEEgCUkG-nH4Ui1IsBvPCEIig_UhHn-OtJ9ZHnGmQnRQo22VMRWa9WPXYBt4RCA3eljmDYXLfQNua8Z69e40cGoXrSza90KsuXqNLo-0xQ0w
-
Found the problem! I had this function, used to build a key from E&N: function BNfromBase64(const _s : String) : PBIGNUM; var len : integer; decoded : ansistring; begin decoded := IcsBase64UrlDecode(_s); len := length(decoded); result := BN_bin2bn(@decoded[1], len, nil); end; It was returning rubbish from IcsBase64UrlDecode under Linux, hence the length (which I had to calculate on a separate line to be able to see it in debugger) was fluctuating. I have replaced IcsBase64UrlDecode with TNetEncoding.Base64.DecodeStringToBytes (also changing the type from ansistring to tbytes and the index in the final call to 0 from 1) and it's fixed 😉 So, ICS version of IcsBase64UrlDecode is not Linux-proof, you should take note. From what I could see in the debugger, it was treating the string as 0-based and ansichar as a word, although that could be a Linux debugger's quirk.
-
And typically Linux: OpenSSL 3.3.2 breaks yum and has a new dependency on libcurl (which I cannot install because of yum issue)... Had to rebuild SSL with MD, because of libldap.so, used by yum, so I can install libcurl. So, I now have the latest OpenSSL 3.3.2 here, but still the same error: error:02000077:rsa routines::wrong signature length error:1C880004:Provider routines::RSA lib Same, even if I eliminate any possibility of typecasting issues & even hard-code 256 size to avoid using Length(), as in: ret := EVP_DigestVerify(DigestCtx, @OldDigest[0], 256, PAnsiChar(Data), Length(Data)); Same works under Win32 & Win64...
-
Yes, pretty much. Except that I was not creating this JWT, it's someone else's. It does validate using the same code under Windows. - "used it with IcsAsymVerifyDigestTB without any string, encoding or base64 conversions" And yes, it's 256 bytes long, binary digest I'm passing in. So far I triple-checked the OpenSSL function definition, data types/sizes, etc. Binary stream is the same under Windows, BTW, so I know it comes through exactly the same here. I'm trying to build the latest SSL now, to see if that was just a 3.0 bug...
-
Irrespective of that, even if all the right data is sent to OpenSSL's EVP_DigestVerify function, unlike Windows, in Linux it fails - returns 0 and those messages...
-
Yes, but as per my earlier message, that one cast may be sufficient to kill it. Now I have rewritten all parts involved in this one atomic process to replace pansichar with pointer and I'm copying raw data, so there can be no character conversions anywhere here, including in the EVP_DigestVerify definition and I'm watching memory and can see it all makes through as intended. And yet, the same error. It works under Windows, BTW, with the same values.
-
Here's a simple test: (OldDigest is TBytes, lll is integer) lll := Length(PAnsiChar(OldDigest)); // 52 lll := Length(OldDigest); // 256 That cast does kill it...