|
Post by Chris Iverson on Jun 6, 2018 12:40:21 GMT -5
Short term, support for clientside authentication using certificates, as well as the ability to import certs.
While neither of these are widely-used features, having certificate manipulation will be necessary for the long term plan: server-side versions of everything, which will require being able to provide a cert or cert chain to the client upon connection request. Therefore, having the ability to import and use certs directly is already necessary.
Longer term, multiple server connection support, meaning the ability to handle multiple simultaneous connections at once to the server. It won't be truly simultaneous, as that would require threaded programming which LB just doesn't do, but even if you're only able to actually work on one at a time, the ability to manage contexts for multiple clients at once would be invaluable.
|
|
fwm
Full Member
Posts: 105
|
Post by fwm on Jun 6, 2018 14:49:18 GMT -5
Hi Chris,
Wow - so eventually we'll be able to use this wrapper to create a server that can serve secure content?
Do you think that the certificates will be able to be provided from, say, a .pem or .crt file, or will they need to have been added to one of the certificate stores on the machine already?
Keith.
|
|
|
Post by Chris Iverson on Jun 6, 2018 15:46:52 GMT -5
That's the idea.
Ideally, I'd support PEM/CRT, PFX, p12, etc. as well as having the certs loaded in the Windows CertStore. It certainly would make things more convenient.
|
|
fwm
Full Member
Posts: 105
|
Post by fwm on Jun 8, 2018 14:30:31 GMT -5
Chris,
Quick question - and it might be outside of the remit of the SChannel project but if so perhaps you can advise...
Is it possible or feasible to add a ping function to this? I am sometimes wanting to quickly ping a server before connecting to test its response time.
Or would it make better sense to keep that separate from this? Similarly to SSL/TLS, I can't find anything for pinging from LB, aside from using a run command to run the system "ping" command which is quite slow and the result has to be written to a text file and then read back in which is not very reliable.
I'd be interested in your thoughts on this.
Thanks, Keith.
|
|
|
Post by Chris Iverson on Jun 8, 2018 15:35:21 GMT -5
That would probably be a good idea. While Windows does provide an API for making such a call(ICMPSendEcho), it should be noted that 1) that requires some of the same struct/memory manipulation that caused me to make a wrapper for Winsock in the first place, since LB isn't too elegant with those, and 2) the actual structs/etc and final API calls change depending on if it's IPv4 or IPv6(ICMPCreateFile, ICMPSendEcho2 vs ICMP6CreateFile, ICMP6SendEcho2), along with an additional parameter needed by the IPv6 version that'll be easier for C code to obtain(it needs a local address to send from, due to the way IPv6 allocation works; IPv4 will just use the system default).
|
|
|
Post by Carl Gundel on Jun 9, 2018 13:13:03 GMT -5
That would probably be a good idea. While Windows does provide an API for making such a call(ICMPSendEcho), it should be noted that 1) that requires some of the same struct/memory manipulation that caused me to make a wrapper for Winsock in the first place, since LB isn't too elegant with those, and 2) the actual structs/etc and final API calls change depending on if it's IPv4 or IPv6(ICMPCreateFile, ICMPSendEcho2 vs ICMP6CreateFile, ICMP6SendEcho2), along with an additional parameter needed by the IPv6 version that'll be easier for C code to obtain(it needs a local address to send from, due to the way IPv6 allocation works; IPv4 will just use the system default). Chris, I really appreciate you working on this, thanks. Do you have a blog? You might consider writing about what you're doing, and if you don't have a blog, I'd be more than pleased to post something from you as a guest author. :-)
|
|
|
Post by Chris Iverson on Jun 9, 2018 23:33:44 GMT -5
I've considered starting one for a while now. I'd probably try hosting it myself, just to give myself one more thing to play with and figure out.
|
|
fwm
Full Member
Posts: 105
|
Post by fwm on Jun 13, 2018 6:42:33 GMT -5
I would love for you to start a blog as I've found this project really interesting - it has also let me into the world of programming outside of Liberty Basic... ...not that I am thinking of abandoning LB and moving to another language - I think LB will always be my programming language of choice! I'm looking forward to seeing the next stage of this wrapper project too - giving LB the ability to ping a server and send a server certificates to validate itself is going to be quite incredible I wonder if anyone else has started to play about with this wrapper DLL yet? Keith
|
|
fwm
Full Member
Posts: 105
|
Post by fwm on Jun 16, 2018 12:48:08 GMT -5
Hi Chris,
Hope all is going well. I was just wondering if it would be worth publishing a compiled/built version of the DLL with the current functionality so that others can have a go programming with it? Or are you wanting to wait until you have finished adding the additional functionality to it?
Keith
|
|
fwm
Full Member
Posts: 105
|
Post by fwm on Jun 17, 2018 13:59:13 GMT -5
Chris,
Apologies for the stream of comments... I keep thinking of things to say!
I would like to go back to the functionality of the wrapper for a moment if possible. I'm wondering if there's any way to alter the Receive and DecryptReceive functions to allow for a looped call to them until they are empty, in other words so that there isn't a hard limit on the size of data they can return.
For example, currently we use something like this (I've rewritten the functions slightly for my own use):
Function Receive$(socket) bufLen = 4096 buf$ = space$(bufLen) CallDLL #SSL, "Receive",_ socket as long,_ buf$ as ptr,_ bufLen as long,_ length as long Receive$ = left$(buf$, length) End Function
However, I think it would be good to use a smaller buffer and loop the receiving until nothing is left, in case we want to retrieve a large web page or similar, like this:
Function Receive$(socket) bufLen = 512 buf$ = space$(bufLen) Receive$ = "" do CallDLL #SSL, "Receive",_ socket as long,_ buf$ as ptr,_ bufLen as long,_ length as long if length = 0 then exit do Receive$ = Receive$ + left$(buf$, length) loop until 0 End Function
The problem with using this at the moment is that as soon as there is no more data for the Receive function to read, the LB program hangs - and I guess that's because the wrapper isn't written to handle this approach right now?
Or alternatively, could the wrapper function differently so that if a buffer is specified, that amount of data is returned, and if the buffer is set to 0, then the data is not limited and all available data is returned (for large pages or where the amount of data is unknown)?
I've quoted the Receive function but as I said above I think it would be great if it was possible with both the Receive and DecryptReceive functions.
Again I would love to hear your thoughts and I hope that this all makes sense but if it doesn't let me know!
Keith.
|
|
|
Post by Chris Iverson on Jun 18, 2018 9:59:41 GMT -5
I've been thinking about the Receive() thing myself. Ideally, you should be inspecting the data read so you know when to stop reading(different protocols will indicate end-of-data in different ways), but that's not always possible. In theory, either the protocol will state the length of the transferred data, or it will have a blank line(CRLF+CRLF) at the end of it. And connections aren't usually kept open long unless they're being actively utilized; if there's no more data to send, and the client doesn't request any more, the server closes the connection, which causes the client's recv() to return with 0 data read.
I could rewrite Receive() to be non-blocking(or at least, not-blocking-long), but then your code needs to be able to handle cases where no data is returned. Actually, if you're using DecryptReceive(), you need to be able to handle that, anyway, because while receiving nothing from a recv() call means the server disconnected, returning nothing from a DecryptMessage() call means the connection is still active, but the only data transmitted was TLS session data, no application data(i.e. none of YOUR data was transferred; just stuff to do with maintaining the TLS session).
I could also add a wrapper around the select() call, so you can poll to check if the socket has data ready to be read.
As for the buffers, the problem comes down to memory management - and I'm honestly not sure how the mesock DLL managed to handle this, if it did at all.
Something needs to create the fixed-size buffers used to retrieve data from the recv() and the DecryptMessage() API calls. Those API calls only take a fixed buffer size, and will only copy data into the buffer as far as you specify.
If you specify a buffer size of 0 to any of those API calls, they will fail indicating the buffer isn't large enough.
I can handle generating the buffers myself, and just passing them back to the application(for the unlimited buffer size), but that runs into the issues of 1) needing to know when to free the buffer when you're done with it, 2) figuring out how to pass binary data, and 3) changing how the DLL call works based on the parameters, meaning you sometimes need to free a buffer and sometimes don't.
My DLL would need to allocate memory to satisfy those "unlimited" requests - memory that isn't taken from LB. Therefore, it needs to free the memory once you're done with it. If not, then as you use the DLL more and more, more and more memory would be used and unavailable(i.e. a memory leak). Therefore, I would need to add another DLL call to free the memory returned from the Receive() functions, but only if you called it in a way that allocated memory. You'd need to remember to call that each time.
The second issue is that, quite likely, it wouldn't be able to handle binary data very well(i.e. transferring files over sockets, for example).
The reason for this is that LB doesn't have the ability to directly dereference a pointer, except for winstring() and an API call.
If you use winstring() to do the dereference(this is what mesock did), you run into the issue of it looking specifically for a string. There's no way to tell it HOW much data you want to read from a buffer; it treats the buffer as a string, and stops at the first null-byte. This means that if you're transferring files or other binary data, you lose everything in the buffer after the first null-byte.
The other method is to use an API call to copy the memory bytes directly - RtlCopyMemory(). This has the advantage of having you specify a size, which means you copy exactly as much as you need to, but has the disadvantage of needing YOU to set up buffers to copy into, which means you're right back where you started: managing buffers.
|
|
fwm
Full Member
Posts: 105
|
Post by fwm on Jun 19, 2018 7:21:22 GMT -5
Hmmm sounds complicated but you sound like you know what you're talking about! It's great that you're still taking the time to look at this and develop it further, so thank you again. Keith
|
|
|
Post by Mark Dunham on Jun 20, 2018 11:23:22 GMT -5
Chris and Keith,
I this is a great thread. I am hoping to get sometime soon to sit down and play with the .dll. My brother is wondering if there is a way to make an online game we can both play so I think your project may help get me closer to what he asked just need the time to play. Great work...
|
|
fwm
Full Member
Posts: 105
|
Post by fwm on Jun 20, 2018 12:41:38 GMT -5
I agree Mark, it's a great project but all the credit goes to Chris - he's the genius behind the DLL!
Keith.
|
|
|
Post by Chris Iverson on Jun 20, 2018 17:46:59 GMT -5
Ah, missed a suggestion earlier. Yeah, I should include a build of the DLL somewhere, to make it easy to obtain and play with.
Also, if I start blogging about my dev process while continuing this, what sorts of info would you be interested in? And would you want any coverage of what I've written on it so far? What would you want it to cover?
|
|