-
Mar 7th, 2018, 09:26 AM
#1
SSPI/Schannel client for SSL/TLS channels in VB6
https://github.com/wqweto/VbAsyncSocket
FYI, these are generic/thin WinSock API wrappers for non-blocking sockets (that optionally can even block if desired), very similar to CAsyncSocket/CSocket classes from olden MFC C++ library.
The repo also includes a cTlsClient class (~850 LOC) under `contrib` folder, which implements SSL/TLS secure sockets using OS provided SSPI/Schannel API for the heavy lifting i.e. w/o any external dependencies. Couldn't find similar simple and reliable implementation in the CodeBank, between all the noise and false positives couttsj's submissions seem to generate on the search topic.
Here is a sample code for STARTTLS over SMTP to smtp.gmail.com port 587
vb Code:
With New cTlsClient
.Connect "smtp.gmail.com", 587
Debug.Print .ReadText();
.WriteText "HELO 127.0.0.1" & vbCrLf
Debug.Print .ReadText();
.WriteText "STARTTLS" & vbCrLf
Debug.Print .ReadText();
.StartTls "smtp.gmail.com"
Debug.Print "TLS handshake complete: " & .TlsHostAddress
.WriteText "QUIT" & vbCrLf
Debug.Print .ReadText();
End With
. . . which produces something like this in Immediate window:
Code:
220 smtp.gmail.com ESMTP l8sm10315047wmf.39 - gsmtp
250 smtp.gmail.com at your service
220 2.0.0 Ready to start TLS
TLS handshake complete: smtp.gmail.com
221 2.0.0 closing connection l8sm10315047wmf.39 - gsmtp
Basicly the sample starts with plain-text communication to the SMTP server which it later upgrades to a TLS secured channel over the same socket, just before sending the final `QUIT` command.
Accessing https servers or any other "SMTP/FTP/Whatever over SSL" servers with instances of this class is even easier as `Connect` method has a `UseTls` parameter for the sole purpose of starting TLS channel automagically immediately after connection is established.
Any suggestions and contributions are always welcome, here or at github!
cheers,
</wqw>
-
Feb 6th, 2019, 04:17 AM
#2
New Member
Re: SSPI/Schannel client for SSL/TLS channels in VB6
Thank you very much for sharing!
I don't speak English, I have to use Google Translate.
Due to the Chinese network blockade. Unable to access some websites, only through proxy server.
I am using your source program.
How to connect to the https page via the socks5 proxy
Code:
'127.0.0.1:1080 is the SOCKS5 proxy server
Set oTlsClient = pvInitHttpRequest("https://www.google.com/", "127.0.0.1", 1080)
Code:
Private Function pvInitHttpRequest(sUrl As String, Optional s5ip$, Optional s5port&) As cTlsClient
'Omit part of the code.....
oRetVal.SetTimeouts 0, 2500, 2500, 2500 'Set timeout parameters
If s5ip$ <> "" And s5port& <> 0 Then 'First connect to the SOCKS5 proxy server
If Not oRetVal.Connect(s5ip$, s5port&, False) Then GoTo QH
Debug.Print Format$(TimerEx, "0.000"), "Start connecting to the proxy server " & s5ip$ & ":" & s5port&
If Not oRetVal.WriteArray(Socks5_Con1) Then GoTo QH
Debug.Print Format$(TimerEx, "0.000"), "First sent to the proxy server"
Dim bytData() As Byte
If Not oRetVal.ReadArray(bytData) Then GoTo QH
Debug.Print Format$(TimerEx, "0.000"), "Receive the data of the proxy server for the first time"
If bytData(1) = 255 Then
Debug.Print Format$(TimerEx, "0.000"), "Connection proxy failed!"
GoTo QH
ElseIf bytData(0) = 5 And bytData(1) = 0 Then 'If the agent replies with 05 00 for no authentication, the connection is successful.
Debug.Print Format$(TimerEx, "0.000"), "The first connection agent was successful! No verification"
Dim iSiT_host As Boolean
iSiT_host = Return_IP_Type(sHost)
If Not oRetVal.WriteText(Socks5_Con2(sHost, lPort, iSiT_host)) Then GoTo QH 'The second step is to verify the connection request
Debug.Print Format$(TimerEx, "0.000"), "Second time sent to the proxy server"
End If
If Not oRetVal.ReadArray(bytData) Then GoTo QH
If bytData(1) = 0 Then 'The second reply from the proxy server
Debug.Print Format$(TimerEx, "0.000"), "Connect to through a proxy server" & sHost & lPort & "success." 'In the last step without verification, the agent replies with the second byte being 00 and the rest being a failure.
'GoTo QH 'Connect OK to start GET or HEAD http request
Else
Debug.Print Format$(TimerEx, "0.000"), "Failed to connect to the target server through a proxy!"
GoTo QH
End If
Else
If Not oRetVal.Connect(sHost, lPort) Then GoTo QH 'Directly connect to the target host when there is no proxy server
Debug.Print Format$(TimerEx, "0.000"), "Connected to " & sHost & ":" & lPort
End If
If LCase$(sProto) = "https" Then
If Not oRetVal.StartTls(sHost) Then GoTo QH 'If it is connected through a proxy "www.google.com:443",How to conduct TLS handshake?
Debug.Print Format$(TimerEx, "0.000"), "TLS handshake complete"
End If
If Not oRetVal.WriteText("GET " & sPath & " HTTP/1.0" & vbCrLf & _
"Host: " & sHost & vbCrLf & _
"Connection: close" & vbCrLf & vbCrLf) Then
GoTo QH
End If
Debug.Print Format$(TimerEx, "0.000"), "Request sent"
Set pvInitHttpRequest = oRetVal
QH:
End Function
oRetVal.StartTls(sHost) =false
After successfully connecting to the target server through the proxy, the handshake always returns false.
Now that something went wrong, what should I do?
-
Feb 6th, 2019, 12:34 PM
#3
Re: SSPI/Schannel client for SSL/TLS channels in VB6
I just implemented SOCKS5 support for https tunneling in the test project and handshake is working ok here.
I have no idea how China's Great Firewall is working (probably whole stateful inspection) but it would be insanely simple to circumvent it w/ a simple SOCKS5 proxy, don't you think? Besides, hosting the proxy on localhost tunnels nothing outside The Firewall.
I'm starting to wonder if the https handshake worked through your connection *without* proxy in first place. If so, you probably messed up SOCKS5 protocol implementation some place -- half of the code is missing in your post, so can't easily tell what went wrong.
Anyway, SOCKS5 proxy is now impl ok in the Basic test I linked above.
cheers,
</wqw>
Last edited by wqweto; Feb 6th, 2019 at 12:39 PM.
-
Feb 7th, 2019, 05:37 AM
#4
New Member
Re: SSPI/Schannel client for SSL/TLS channels in VB6
Thank you very much, with your example you can connect via socks5. And my previous aspects are not good. I have been unable to find the problem, maybe there is a problem here, ignore it. Just use your source program
oRetVal.WriteText Chr(5) & Chr(1) & Chr(0) & Chr(3) & Chr(Len(Dest_Address)) & _
Dest_Address & Chr(Int(DestPort / 256)) & Chr(DestPort Mod 256)
A little,lPort = Val(.Item(2)) Changed to lPort = Val(Mid(.Item(2), 2)) better
Next, I am going to use the http proxy to get the https page.
-
Feb 7th, 2019, 08:09 AM
#5
Re: SSPI/Schannel client for SSL/TLS channels in VB6
Fixed and thank you for the bug report!
While on fixing url parsing I used the opportunity to add user/pass authentication against the SOCKS5 proxy too.
cheers,
</wqw>
-
Feb 7th, 2019, 09:41 AM
#6
New Member
Re: SSPI/Schannel client for SSL/TLS channels in VB6
It is not a mistake to parse this with url. It's just that the operating environment is different. Like here,
I must change "Connection: close" change into "Connection: Keep-Alive"
Code:
If Mid$(sHeaders, 10, 3) = "302" Then
change into
Code:
If Mid$(sHeaders, 10, 2) = "30" Then
Code:
oRetVal.WriteArray pvToByteArray(5, 1, 0, 3) '--- 5 = version, 1 = TCP stream conn, 0 = reserved, 3 = domain name
baBuffer = oRetVal.Socket.ToTextArray(sHost, ucsScpUtf8)"
oRetVal.WriteArray pvToByteArray(UBound(baBuffer) + 1)
change into
Code:
addresstype% = 3
If IsNumeric(Split(StrReverse(sHost), ".")(0)) Then
addresstype% = 1
End If '0x01: IPv4 address 0x03: Domain name
oRetVal.WriteArray pvToByteArray(5, 1, 0, addresstype%) '--- 5 = version, 1 = TCP stream conn, 0 = reserved, 3 = domain name
If addresstype% = 1 Then
ReDim baBuffer(3)
baBuffer(0) = Split(sHost, ".")(0)
baBuffer(1) = Split(sHost, ".")(1)
baBuffer(2) = Split(sHost, ".")(2)
baBuffer(3) = Split(sHost, ".")(3)
Else
baBuffer = oRetVal.Socket.ToTextArray(sHost, ucsScpUtf8)
'baBuffer = StrConv(sHost, vbFromUnicode)
oRetVal.WriteArray pvToByteArray(UBound(baBuffer) + 1)
End If"
-
Feb 7th, 2019, 12:52 PM
#7
Re: SSPI/Schannel client for SSL/TLS channels in VB6
> I must change "Connection: close" change into "Connection: Keep-Alive"
That would be very different to implement -- parsing the response has to be redone to depend on Content-Length header I think.
Parsing direct IPs in URL is nice feature to have. I was (secretly) hoping that passing "IP address" to SOCKS5 server as "domain name" would fool the server to "resolve" it to the same IP address :-))
Recognizing 301 vs 302 redirects seems useful addition too.
So this proofs the sample code is very bare. It's just a test for the cAsyncSocket class that might be used as a starting point for full protocol implementation if anyone is willing to read the RFCs and test, test, test. . .
cheers,
</wqw>
-
Mar 26th, 2019, 10:07 AM
#8
Re: SSPI/Schannel client for SSL/TLS channels in VB6
FYI, now VbAsyncSocket repo includes a Winsock control replacement implementation in contrib.
cheers,
</wqw>
-
Nov 23rd, 2021, 05:08 PM
#9
Junior Member
Re: SSPI/Schannel client for SSL/TLS channels in VB6
Originally Posted by wqweto
Code:
Public Sub SendData(data As Variant)
Const FUNC_NAME As String = "SendData"
On Error GoTo EH
Select Case VarType(data)
Case vbString
m_baSendBuffer = pvSocket.ToTextArray(CStr(data), ucsScpAcp)
Case vbByte + vbArray
m_baSendBuffer = data
Case Else
Err.Raise vbObjectError, , "Unsupported data type: " & TypeName(data)
End Select
If UBound(m_baSendBuffer) >= 0 Then
m_lSendPos = 0
m_oSocket_OnSend
End If
Exit Sub
EH:
PrintError FUNC_NAME
End Sub
I'm actually currently still using a variant of CSocket, so maybe it differs from the original Winsock control in this regard, but I think .SendData should not implicitly reset the buffer if there's still unsent data in it. But if the original does it too then well, it's stupid but you have to do it if it's supposed to be a drop-in replacement.
I'll see how much work it is to switch my project over to this. My CSocket evolved over time to support IPv6 and SSL via openssl, but the idea of getting rid of that dependency is tempting. I'm surprised you mention this would support even NT4.0 with mdTlsThunks - I still see a lot of calls to stuff from advapi32; it's not using any fancy new flags, ciphers and hashes and stuff that NT4 wouldn't understand?
-
Nov 24th, 2021, 04:20 AM
#10
Re: SSPI/Schannel client for SSL/TLS channels in VB6
Originally Posted by Zahl
I'm actually currently still using a variant of CSocket, so maybe it differs from the original Winsock control in this regard, but I think .SendData should not implicitly reset the buffer if there's still unsent data in it. But if the original does it too then well, it's stupid but you have to do it if it's supposed to be a drop-in replacement.
Yes, you have a point and this looks like a bug. It's not present when using TLS socket because the underlying encrypting routines buffer the whole output so m_baSendBuffer never has outstanding data.
I'll look to it to append to m_baSendBuffer if m_lSendPos indicates there is some unsent data in it.
Edit: Fixed in 845f387
Originally Posted by Zahl
I'll see how much work it is to switch my project over to this. My CSocket evolved over time to support IPv6 and SSL via openssl, but the idea of getting rid of that dependency is tempting. I'm surprised you mention this would support even NT4.0 with mdTlsThunks - I still see a lot of calls to stuff from advapi32; it's not using any fancy new flags, ciphers and hashes and stuff that NT4 wouldn't understand?
I test it in couple of VMs with NT4, Win2000, XP, Vista, etc. with "Break on All Errors" set in the IDE. The code has extensive checks on API calls return values so these are raised as VB errors too.
For the latest WinHttpRequest replacement effort I had time to test it on an XP only for the TLS 1.3 support. More tests with earlier OS versions are to be done for any API calls incompatibility.
Edit: CSocket is equivalent to cTlsSocket class, not the ctxWinsock control. cTlsSocket class contrary to its name can create both encrypted and plaintext sockets both in async and blocking mode.
cheers,
</wqw>
Last edited by wqweto; Nov 24th, 2021 at 07:30 AM.
-
Jul 13th, 2022, 06:28 AM
#11
Registered User
Re: SSPI/Schannel client for SSL/TLS channels in VB6
Hi wqweto,
Thanks for your great code.
I am trying to find out any solution which for VB6 with TLS function.
And I found the topic and your code.
But I would like to receive mail from Microsoft Exchange POP3 which TLS required.
Does your project support the POP3 with TLS?
Cheers,
Eric Hu
-
Jul 14th, 2022, 02:41 AM
#12
Re: SSPI/Schannel client for SSL/TLS channels in VB6
Originally Posted by ieric.hu
Does your project support the POP3 with TLS?
It does support TLS encryption for any TCP based protocol but does not explicitly support POP3 protocol (nor SMTP).
There is a cHttpRequest class (in contrib directory) which implements client-side HTTP so you get HTTP over TLS (so called HTTPS) implemented with it.
But there is no separate class which implements POP3 over TLS in the repo. You can implement such class using cTlsSocket class for the network transport and you'll get TLS baked in for free.
cheers,
</wqw>
-
Jul 14th, 2022, 06:10 PM
#13
Registered User
Re: SSPI/Schannel client for SSL/TLS channels in VB6
Hi wqweto,
Thanks for your reply and explanation for it.
I will try on it
Thanks!
Eric Hu
-
May 7th, 2023, 09:57 AM
#14
New Member
Re: SSPI/Schannel client for SSL/TLS channels in VB6
Hi,
I have a application in VB6. It uses the Socket6 to create connection to a POP3/SMTP server, loads newly arrived mails and sends new created mails. Its now running since several years without problems.
Now I have to alter the socket to another one enabling SSL/TLS. I am not very familliar with TCP a.s.o. I checked a lot of internet pages and found the VbAsyncSocket. However I am not sure if this product is the right one for my project. My application has to run on XP, Win7, Win10 and Win11.
Can you help me?
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|