This is an old revision of the document!
Fetching a secure web page
by Richard Russell, July 2009
The procedure listed below fetches the contents of a secure (https:) web page to a specified file; it uses the OpenSSL library and requires the files libssl32.dll and libeay32.dll to be available. They can be downloaded in this Zip file, from which they should be extracted and copied to a location where they will be found by LoadLibrary, i.e. one of:
- The directory from which the application will be loaded (@dir$).
- The 'current' directory.
- The system directory (e.g. C:\Windows\System32\).
- The Windows directory (e.g. C:\Windows\).
- One of the directories listed in the PATH environment variable.
If you want to distribute libssl32.dll and libeay32.dll with your application then store them in @dir$ and embed them in the executable. Alternatively you can put them in @lib$ (or a sub-directory) but in that case you will need to amend the procedure below to load them explicitly from that location.
The procedure should be called in the following context:
port$ = "443" : REM https host$ = "www.fortify.net" page$ = "/sslcheck.html" file$ = @tmp$ + "sslcheck.html" PROCsslfetch(port$, host$, page$, file$)
This fetches the page https://www.fortify.net/sslcheck.html to the file sslcheck.html.
Here is the procedure:
DEF PROCsslfetch(port$, host$, page$, file$) LOCAL libssl%, libeay%, meth%, ctx%, sock%, temp%, res%, ssl%, sbio%, file% LOCAL req$, buf&()
FIONBIO = &8004667E BIO_NOCLOSE = 0 BUFSIZ = 256
ON ERROR LOCAL RESTORE ERROR : INSTALL @lib$+"SOCKLIB" PROC_initsockets
SYS "LoadLibrary", "libssl32.dll" TO libssl% IF libssl% = 0 PROCsslcleanup : ERROR 100, "Cannot load LIBSSL32.DLL" SYS "GetProcAddress", libssl%, "SSL_library_init" TO `SSL_library_init` SYS "GetProcAddress", libssl%, "SSLv23_method" TO `SSLv23_method` SYS "GetProcAddress", libssl%, "SSL_CTX_new" TO `SSL_CTX_new` SYS "GetProcAddress", libssl%, "SSL_new" TO `SSL_new` SYS "GetProcAddress", libssl%, "SSL_set_bio" TO `SSL_set_bio` SYS "GetProcAddress", libssl%, "SSL_connect" TO `SSL_connect` SYS "GetProcAddress", libssl%, "SSL_write" TO `SSL_write` SYS "GetProcAddress", libssl%, "SSL_read" TO `SSL_read` SYS "GetProcAddress", libssl%, "SSL_CTX_free" TO `SSL_CTX_free`
SYS "LoadLibrary", "libeay32.dll" TO libeay% IF libeay% = 0 PROCsslcleanup : ERROR 100, "Cannot load LIBEAY32.DLL" SYS "GetProcAddress", libeay%, "BIO_new_socket" TO `BIO_new_socket`
REM Global system initialisation: SYS `SSL_library_init`
REM Create SSL context: SYS `SSLv23_method` TO meth% SYS `SSL_CTX_new`, meth% TO ctx% IF ctx% = 0 PROCsslcleanup : ERROR 100, "SSL_CTX_new failed"
REM Connect the TCP socket: sock% = FN_tcpconnect(host$, port$) IF sock% < 0 PROCsslcleanup : ERROR 100, "Cannot connect to " + host$
temp% = 0 SYS `ioctlsocket`, sock%, FIONBIO, ^temp% TO res% IF res% PROCsslcleanup : ERROR 105, "Cannot set socket to blocking"
REM Connect the SSL socket: SYS `SSL_new`, ctx% TO ssl% SYS `BIO_new_socket`, sock%, BIO_NOCLOSE TO sbio% SYS `SSL_set_bio`, ssl%, sbio%, sbio%
SYS `SSL_connect`, ssl% TO res% IF res% <= 0 PROCsslcleanup : ERROR 100, "SSL connect failed: " + STR$res%
REM Request the page: req$ = "GET " + page$ + " HTTP/1.0" + CHR$13 + CHR$10 req$ += "User-Agent: BB4W" + CHR$13 + CHR$10 req$ += "Host: " + host$ + ":" + port$ + CHR$13 + CHR$10 req$ += CHR$13 + CHR$10
SYS `SSL_write`, ssl%, req$, LEN(req$) TO res% IF res% <> LEN(req$) PROCsslcleanup : ERROR 100, "SSL write failed: " + STR$res%
REM Copy the requested page to a file: DIM buf&(BUFSIZ-1)
file% = OPENOUT(file$) REPEAT SYS `SSL_read`, ssl%, ^buf&(0), BUFSIZ TO res% IF res% > 0 SYS "WriteFile", @hfile%(file%), ^buf&(0), res%, ^temp%, 0 UNTIL res% <= 0 CLOSE #file% IF res% PROCsslcleanup : ERROR 100, "SSL read failed: " + STR$res%
REM Tidy up before exit: PROCsslcleanup ENDPROC
DEF PROCsslcleanup sock% += 0 : IF sock% PROC_closesocket(sock%) : sock% = 0 ctx% += 0 : IF ctx% SYS `SSL_CTX_free`, ctx% : ctx% = 0 libssl% += 0 : IF libssl% SYS "FreeLibrary", libssl% : libssl% = 0 libeay% += 0 : IF libeay% SYS "FreeLibrary", libeay% : libeay% = 0 PROC_exitsockets ENDPROC