TLS Networking Using LibTLS

Share your advanced PureBasic knowledge/code with the community.
Opcode
Enthusiast
Enthusiast
Posts: 137
Joined: Thu Jul 18, 2013 4:58 am

TLS Networking Using LibTLS

Post by Opcode »

Windows:
You will need four files from the LibreSSL package: https://ftp.openbsd.org/pub/OpenBSD/Lib ... indows.zip
Note: This is an old (but only) precompiled build of LibreSSL for Windows. If you can, build a newer version!
  • libtls-15.lib
  • libtls-15.dll
  • libssl-43.dll
  • libcrypto-41.dll
Placed in the same directory as the PB files.

Ubuntu:

Code: Select all

sudo apt update
sudo apt install libtls-dev
Main.pb

Code: Select all

DeclareModule Gateway
  
  XIncludeFile "LibTLS.pbi"
  
  Global *ctx, *cfg
  
  Macro SendNetworkData(Connection, MemoryBuffer, Length)
    tls_write(*ctx, *MemoryBuffer, Length)
  EndMacro
  
  Macro ReceiveNetworkData(Connection, DataBuffer, DataBufferLength)
    tls_read(*ctx, *DataBuffer, DataBufferLength)
  EndMacro
  
  Declare Main()
  
EndDeclareModule

Module Gateway
  
  Procedure Main()
    
    Protected *FrameBuffer = AllocateMemory(1024)
    
    OpenConsole()
    
    ; ------------------------------------------------------------
    ;   Setup LIBTLS
    ; ------------------------------------------------------------
    
    If tls_init() = -1
      PrintN(PeekS(tls_error(*ctx), -1, #PB_Ascii)) : Input() : End
    EndIf
    
    *cfg = tls_config_new()
    If *cfg = #Null
      PrintN(PeekS(tls_error(*ctx), -1, #PB_Ascii)) : Input() : End
    EndIf
    
    ; We are not going to verify with the server (otherwise set your certs here)
    tls_config_insecure_noverifycert(*cfg)
    tls_config_insecure_noverifyname(*cfg)
    
    ; Set which protocol we're going to use (TLS v1.2)
    If tls_config_set_protocols(*cfg, #TLS_PROTOCOL_TLSv1_2) = -1
      PrintN(PeekS(tls_error(*ctx), -1, #PB_Ascii)) : Input() : End
    EndIf
    
    ; Set context as a client
    *ctx = tls_client()
    If *ctx = #Null
      PrintN(PeekS(tls_error(*ctx), -1, #PB_Ascii)) : Input() : End
    EndIf
    
    ; Apply our configuration to the tls context
    If tls_configure(*ctx, *cfg) = -1
      PrintN(PeekS(tls_error(*ctx), -1, #PB_Ascii)) : Input() : End
    EndIf
    
    ; ------------------------------------------------------------
    ;   Typical Network Program
    ; ------------------------------------------------------------
    
    request.s = "GET /raw HTTP/1.1"                           + #CRLF$ +
                "Host: ws.postman-echo.com"                   + #CRLF$ +
                "Upgrade: websocket"                          + #CRLF$ +
                "Connection: Upgrade"                         + #CRLF$ +
                "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" + #CRLF$ +
                "Sec-WebSocket-Version: 13"                   + #CRLF$ + #CRLF$
    
    socket = OpenNetworkConnection("ws.postman-echo.com", 443)
    If socket
      
      If tls_connect_socket(*ctx, ConnectionID(socket), "abc") = 0 ; This Being The Exception
        
        PokeS(*FrameBuffer, request, StringByteLength(request, #PB_UTF8), #PB_UTF8)
        
        size = SendNetworkData(socket, FrameBuffer, StringByteLength(request))
        If size
          
          FillMemory(*FrameBuffer, 1024)
          
          Repeat
            recv = ReceiveNetworkData(socket, FrameBuffer, 1024)
            answer$ = answer$ + PeekS(*FrameBuffer, recv, #PB_UTF8)
          Until FindString(answer$, #CRLF$ + #CRLF$)
          
          PrintN(answer$)
          
          ; Check Answer
          If FindString(answer$, "HTTP/1.1 101", 1, #PB_String_NoCase) And
             FindString(answer$, "Upgrade: websocket", 1, #PB_String_NoCase) And
             FindString(answer$, "Connection: Upgrade", 1, #PB_String_NoCase)
            PrintN("Connection upgraded, now do whatever...")
          EndIf
          
          Input() : End
        EndIf
        
      EndIf
      
    EndIf
    
  EndProcedure
  
EndModule

Gateway::Main()
LibTLS.pbi

Code: Select all

; /* $OpenBSD: tls.h,v 1.58 2020/01/22 06:44:02 beck Exp $ */
; /*
;  * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
;  *
;  * Permission To use, copy, modify, And distribute this software For any
;  * purpose With Or without fee is hereby granted, provided that the above
;  * copyright notice And this permission notice appear in all copies.
;  *
;  * THE SOFTWARE IS PROVIDED "AS IS" And THE AUTHOR DISCLAIMS ALL WARRANTIES
;  * With REGARD To THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
;  * MERCHANTABILITY And FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE For
;  * ANY SPECIAL, DIRECT, INDIRECT, Or CONSEQUENTIAL DAMAGES Or ANY DAMAGES
;  * WHATSOEVER RESULTING FROM LOSS OF USE, Data Or PROFITS, WHETHER IN AN
;  * ACTION OF CONTRACT, NEGLIGENCE Or OTHER TORTIOUS ACTION, ARISING OUT OF
;  * Or IN CONNECTION With THE USE Or PERFORMANCE OF THIS SOFTWARE.
;  */

Macro const : p-utf8 : EndMacro

#TLS_API = 20200120

#TLS_PROTOCOL_TLSv1_0 = (1 << 1)
#TLS_PROTOCOL_TLSv1_1 = (1 << 2)
#TLS_PROTOCOL_TLSv1_2 = (1 << 3)
#TLS_PROTOCOL_TLSv1_3 = (1 << 4)

#TLS_PROTOCOL_TLSv1 = (#TLS_PROTOCOL_TLSv1_0 | #TLS_PROTOCOL_TLSv1_1 | #TLS_PROTOCOL_TLSv1_2 | #TLS_PROTOCOL_TLSv1_3)

#TLS_PROTOCOLS_ALL     = #TLS_PROTOCOL_TLSv1
#TLS_PROTOCOLS_DEFAULT = (#TLS_PROTOCOL_TLSv1_2 | #TLS_PROTOCOL_TLSv1_3)

#TLS_WANT_POLLIN  = -2
#TLS_WANT_POLLOUT = -3

;/* RFC 6960 Section 2.3 */
#TLS_OCSP_RESPONSE_SUCCESSFUL    = 0
#TLS_OCSP_RESPONSE_MALFORMED     = 1
#TLS_OCSP_RESPONSE_INTERNALERROR = 2
#TLS_OCSP_RESPONSE_TRYLATER      = 3
#TLS_OCSP_RESPONSE_SIGREQUIRED   = 4
#TLS_OCSP_RESPONSE_UNAUTHORIZED  = 5

;/* RFC 6960 Section 2.2 */
#TLS_OCSP_CERT_GOOD    = 0
#TLS_OCSP_CERT_REVOKED = 1
#TLS_OCSP_CERT_UNKNOWN = 2

;/* RFC 5280 Section 5.3.1 */
#TLS_CRL_REASON_UNSPECIFIED            = 0
#TLS_CRL_REASON_KEY_COMPROMISE         = 1
#TLS_CRL_REASON_CA_COMPROMISE          = 2
#TLS_CRL_REASON_AFFILIATION_CHANGED    = 3
#TLS_CRL_REASON_SUPERSEDED             = 4
#TLS_CRL_REASON_CESSATION_OF_OPERATION = 5
#TLS_CRL_REASON_CERTIFICATE_HOLD       = 6
#TLS_CRL_REASON_REMOVE_FROM_CRL        = 8
#TLS_CRL_REASON_PRIVILEGE_WITHDRAWN    = 9
#TLS_CRL_REASON_AA_COMPROMISE          = 10

#TLS_MAX_SESSION_ID_LENGTH = 32
#TLS_TICKET_KEY_SIZE       = 48

PrototypeC tls_read_cb(*_ctx, *_buf, _buflen, *_cb_arg)
PrototypeC tls_write_cb(*_ctx, *_buf, _buflen, *_cb_arg)

CompilerIf #PB_Compiler_OS = #PB_OS_Windows
  #LIBRESSLPATH = "libtls-15.lib"
CompilerElse
  #LIBRESSLPATH = "-ltls"
CompilerEndIf

ImportC #LIBRESSLPATH
  tls_init()
  tls_config_error(*config)
  tls_error(*ctx)
  tls_config_new()
  tls_config_free(*config)
  tls_default_ca_cert_file()
  tls_config_add_keypair_file(*config, *_cert_file.const, *_key_file.const)
  tls_config_add_keypair_mem(*config, *_cert.const, _cert_len.i, *_key.const, _key_len.i)
  tls_config_add_keypair_ocsp_file(*config, *_cert_file.const, *_key_file.const, *_ocsp_staple_file.const)
  tls_config_add_keypair_ocsp_mem(*config, *_cert.const, _cert_len.i, *_key.const, _key_len.i, *_staple.const,_staple_len.i)
  tls_config_set_alpn(*config, *_alpn.const)
  tls_config_set_ca_file(*config, *_ca_file.const)
  tls_config_set_ca_path(*config, *_ca_path.const)
  tls_config_set_ca_mem(*config, *_ca.const, _len.i)
  tls_config_set_cert_file(*config, *_cert_file.const)
  tls_config_set_cert_mem(*config, *_cert.const, _len.i)
  tls_config_set_ciphers(*config, *_ciphers.const)
  tls_config_set_crl_file(*config, *_crl_file.const)
  tls_config_set_crl_mem(*config, *_crl.const,_len.i)
  tls_config_set_dheparams(*config, *_params.const)
  tls_config_set_ecdhecurve(*config, *_curve.const)
  tls_config_set_ecdhecurves(*config, *_curves.const)
  tls_config_set_key_file(*config, *_key_file.const)
  tls_config_set_key_mem(*config, *_key.const, _len.i)
  tls_config_set_keypair_file(*config, *_cert_file.const, *_key_file.const)
  tls_config_set_keypair_mem(*config, *_cert.const,_cert_len.i, *_key.const, _key_len.i)
  tls_config_set_keypair_ocsp_file(*config, *_cert_file.const, *_key_file.const, *_staple_file.const)
  tls_config_set_keypair_ocsp_mem(*config, *_cert.const, _cert_len.i, *_key.const, _key_len.i, *_staple.const, staple_len.i)
  tls_config_set_ocsp_staple_mem(*config, *_staple.const, _len.i)
  tls_config_set_ocsp_staple_file(*config, *_staple_file.const)
  tls_config_set_protocols(*config, _protocols.l)
  tls_config_set_session_fd(*config, _session_fd.l)
  tls_config_set_verify_depth(*config, _verify_depth.l)
  tls_config_prefer_ciphers_client(*config)
  tls_config_prefer_ciphers_server(*config)
  tls_config_insecure_noverifycert(*config)
  tls_config_insecure_noverifyname(*config)
  tls_config_insecure_noverifytime(*config)
  tls_config_verify(*config)
  tls_config_ocsp_require_stapling(*config)
  tls_config_verify_client(*config)
  tls_config_verify_client_optional(*config)
  tls_config_clear_keys(*config)
  tls_config_parse_protocols(*_protocols, *_protostr.const)
  tls_config_set_session_id(*config, *_session_id.const, _len.i)
  tls_config_set_session_lifetime(*config, _lifetime.l)
  tls_config_add_ticket_key(*config, _keyrev.i, *_key, _keylen.i)
  tls_client()
  tls_server()
  tls_configure(*ctx, *config)
  tls_reset(*ctx)
  tls_free(*ctx)
  tls_accept_fds(*ctx, *_cctx, _fd_read.l, _fd_write.l)
  tls_accept_socket(*ctx, *_cctx, _socket.l)
  tls_accept_cbs(*ctx, *_cctx, *_read_cb.tls_read_cb, *_write_cb.tls_write_cb, *_cb_arg)
  tls_connect(*ctx, *host.const, *port.const)
  tls_connect_fds(*ctx, _fd_read.l, _fd_write.l, *_servername.const)
  tls_connect_servername(*ctx, *_host.const, *_port.const, *_servername.const)
  tls_connect_socket(*ctx, s.l, *servername.const)
  tls_connect_cbs(*ctx, *_read_cb.tls_read_cb, *_write_cb.tls_write_cb, *_cb_arg,*_servername.const)
  tls_handshake(*ctx)
  tls_read(*ctx, *_buf, _buflen.i)
  tls_write(*ctx, *_buf.const, _buflen.i)
  tls_close(*ctx)
  tls_peer_cert_provided(*ctx)
  tls_peer_cert_contains_name(*ctx, *_name.const)
  tls_peer_cert_hash(*ctx)
  tls_peer_cert_issuer(*ctx)
  tls_peer_cert_subject(*ctx)
  tls_peer_cert_notbefore(*ctx)
  tls_peer_cert_notafter(*ctx)
  tls_peer_cert_chain_pem(*ctx, *_len)
  tls_conn_alpn_selected(*ctx)
  tls_conn_cipher(*ctx)
  tls_conn_cipher_strength(*ctx)
  tls_conn_servername(*ctx)
  tls_conn_session_resumed(*ctx)
  tls_conn_version(*ctx)
  tls_load_file(*_file.const, *_len,*_password)
  tls_unload_file(*_buf, len.i)
  tls_ocsp_process_response(*ctx, *_response.const, _size.i)
  tls_peer_ocsp_cert_status(*ctx)
  tls_peer_ocsp_crl_reason(*ctx)
  tls_peer_ocsp_next_update(*ctx)
  tls_peer_ocsp_response_status(*ctx)
  tls_peer_ocsp_result(*ctx)
  tls_peer_ocsp_revocation_time(*ctx)
  tls_peer_ocsp_this_update(*ctx)
  tls_peer_ocsp_url(*ctx)
EndImport
tls_write() and tls_read() take place of SendNetworkData() and ReceiveNetworkData(). Included are macros to re-route the PB native functions to them for easier install and remove from existing apps. You just have to omit the asterisks in front of the buffers while using them for example:

Code: Select all

SendNetworkData(connection_id, *buffer, len)
becomes:

Code: Select all

SendNetworkData(connection_id, buffer, len)
Should also work on Linux. For a server you would just replace tls_client() with tls_server() and use tls_accept_socket() to associate the tls context with the return of your CreateNetworkServer() (may not work idk).

You can display TLS error messages with something like:

Code: Select all

Debug PeekS(tls_error(*ctx), -1, #PB_Ascii)
There should also be some cleanup like tls_config_free(), tls_close(), tls_free() that you can tie in.
Last edited by Opcode on Sun Mar 26, 2023 4:24 am, edited 19 times in total.
User avatar
idle
Always Here
Always Here
Posts: 5096
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: TLS Client Using LibreSSL [libtls]

Post by idle »

Thanks

I made a static version of libressl 3.5.0 for LiHaSo Webserver Module for windows and linux will just use either the .so or .a
https://www.dropbox.com/s/vfkob35073v6fwv/lweb.zip?dl=0

here's the import and methods I used to make it.in case it helps

Code: Select all

;* $OpenBSD: tls.h,v 1.58 2020/01/22 06:44:02 beck Exp $ */
;*
;* Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
;*
;* Permission To use, copy, modify, And distribute this software For any
;* purpose With Or without fee is hereby granted, provided that the above
;* copyright notice And this permission notice appear in all copies.
;*
;* THE SOFTWARE IS PROVIDED "AS IS" And THE AUTHOR DISCLAIMS ALL WARRANTIES
;* With REGARD To THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
;* MERCHANTABILITY And FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE For
;* ANY SPECIAL, DIRECT, INDIRECT, Or CONSEQUENTIAL DAMAGES Or ANY DAMAGES
;* WHATSOEVER RESULTING FROM LOSS OF USE, Data Or PROFITS, WHETHER IN AN
;* ACTION OF CONTRACT, NEGLIGENCE Or OTHER TORTIOUS ACTION, ARISING OUT OF
;* Or IN CONNECTION With THE USE Or PERFORMANCE OF THIS SOFTWARE.
;*


#TLS_API=	20200120

#TLS_PROTOCOL_TLSv1_0=	(1 << 1)
#TLS_PROTOCOL_TLSv1_1=	(1 << 2)
#TLS_PROTOCOL_TLSv1_2=	(1 << 3)
#TLS_PROTOCOL_TLSv1_3=	(1 << 4)

#TLS_PROTOCOL_TLSv1= #TLS_PROTOCOL_TLSv1_0 | #TLS_PROTOCOL_TLSv1_1 | #TLS_PROTOCOL_TLSv1_2 | #TLS_PROTOCOL_TLSv1_3

#TLS_PROTOCOLS_ALL= #TLS_PROTOCOL_TLSv1
#TLS_PROTOCOLS_DEFAULT= (#TLS_PROTOCOL_TLSv1_2|#TLS_PROTOCOL_TLSv1_3)

#TLS_WANT_POLLIN=	-2
#TLS_WANT_POLLOUT=	-3

;/* RFC 6960 Section 2.3 */
#TLS_OCSP_RESPONSE_SUCCESSFUL=		0
#TLS_OCSP_RESPONSE_MALFORMED=		1
#TLS_OCSP_RESPONSE_INTERNALERROR=		2
#TLS_OCSP_RESPONSE_TRYLATER=		3
#TLS_OCSP_RESPONSE_SIGREQUIRED=		4
#TLS_OCSP_RESPONSE_UNAUTHORIZED=		5

;/* RFC 6960 Section 2.2 */
#TLS_OCSP_CERT_GOOD=			0
#TLS_OCSP_CERT_REVOKED=			1
#TLS_OCSP_CERT_UNKNOWN=			2

;/* RFC 5280 Section 5.3.1 */
#TLS_CRL_REASON_UNSPECIFIED=		0
#TLS_CRL_REASON_KEY_COMPROMISE=		1
#TLS_CRL_REASON_CA_COMPROMISE=		2
#TLS_CRL_REASON_AFFILIATION_CHANGED=	3
#TLS_CRL_REASON_SUPERSEDED=		4
#TLS_CRL_REASON_CESSATION_OF_OPERATION=	5
#TLS_CRL_REASON_CERTIFICATE_HOLD=		6
#TLS_CRL_REASON_REMOVE_FROM_CRL=		8
#TLS_CRL_REASON_PRIVILEGE_WITHDRAWN=	9
#TLS_CRL_REASON_AA_COMPROMISE=		10

#TLS_MAX_SESSION_ID_LENGTH=		32
#TLS_TICKET_KEY_SIZE=			48

;download build from bsd  
;https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.5.0.tar.gz

;Build tools required for windows builds cmake and mingw64
;cmake 
;https://cmake.org/download/ 

;mingw64
;Info https://www.mingw-w64.org/downloads/#llvm-mingw
;Available versions info https://github.com/mstorsjo/llvm-mingw/releases
;Direct download link https://github.com/mstorsjo/llvm-mingw/releases/download/20211002/llvm-mingw-20211002-msvcrt-x86_64.zip

;building on windows linux osx 
;copy the tar file to a folder of your choice, make a subfolder and then extract the tar and cd into the folder
;> mkdir libressl-3.5.0
;> tar -xf libressl-3.5.0.tar.gz
;> cd libressl-3.5.0

;Edit the file libressl-3.5.0\cmakelists and insert option(BUILD_SHARED_LIBS "Build shared" ON) at line 38  
;option(BUILD_SHARED_LIBS "Build shared" ON)

;now make a build folder cd to it and call cmake 
;libressl-3.5.0> mkdir build
;libressl-3.5.0> cd build 

;If OS = Windows
;  libressl-3.5.0\build> cmake -G="MinGW Makefiles"
;  libressl-3.5.0\build> mingw32-make all
;Else 
;  libressl-3.5.0\build> cmake all
;  libressl-3.5.0\build> make all
;EndIf 

PrototypeC tls_read_cb(ctx,*buf,_buflen,*cb_arg);
PrototypeC tls_write_cb(ctx,*buf,_buflen,*cb_arg);

CompilerIf #PB_Compiler_OS = #PB_OS_Windows 
    #LIBRESSLPATH = "libtls-24.lib"
CompilerElse 
    #LIBRESSLPATH = "libtls.a" 
CompilerEndIf       
  
ImportC #LIBRESSLPATH 
  tls_init()                                                                                                   
  tls_config_error(config)                                                                            
  tls_error(ctx)                                                                                      
  tls_config_new()                                                                                             
  tls_config_free(config)                                                                             
  tls_default_ca_cert_file()                                                                                   
  tls_config_add_keypair_file(config,cert_file.p-utf8,key_file.p-utf8)                              
  tls_config_add_keypair_mem(config,cert.p-utf8,certlen.i,key.p-utf8,key_len.i)        
  tls_config_add_keypair_ocsp_file(config,cert_file.p-utf8,key_file.p-utf8,ocsp_staple_file.p-utf8)
  tls_config_add_keypair_ocsp_mem(config,cert.p-utf8,cert_len.i,key.p-utf8,key_len.i,staple.p-utf8,staple_len.i)
  tls_config_set_alpn(config,alpn.p-utf8)                                                                                           
  tls_config_set_ca_file(config,ca_file.p-utf8)                                                                                     
  tls_config_set_ca_path(config,ca_path.p-utf8)                                                                                     
  tls_config_set_ca_mem(config,*ca,len.i)                                                                               
  tls_config_set_cert_file(config,cert_file.p-utf8)                                                                                 
  tls_config_set_cert_mem(config,*cert,len.i)                                                                           
  tls_config_set_ciphers(config,ciphers.p-utf8)                                                                                     
  tls_config_set_crl_file(config,crl_file.p-utf8)                                                                                   
  tls_config_set_crl_mem(config,crl.p-utf8,len.i)                                                                             
  tls_config_set_dheparams(config,params.p-utf8)                                                                                    
  tls_config_set_ecdhecurve(config,curve.p-utf8)                                                                                    
  tls_config_set_ecdhecurves(config,curves.p-utf8)                                                                                  
  tls_config_set_key_file(config,key_file.p-utf8)                                                                                   
  tls_config_set_key_mem(config,*key,len.i)                                                                             
  tls_config_set_keypair_file(config,cert_file.p-utf8,key_file.p-utf8)                                                             
  tls_config_set_keypair_mem(config,cert.p-utf8,cert_len.i,key.p-utf8,key_len.i)                                       
  tls_config_set_keypair_ocsp_file(config,cert_file.p-utf8,key_file.p-utf8,staple_file.p-utf8)                                    
  tls_config_set_keypair_ocsp_mem(config,cert.p-utf8,cert_len.i,key.p-utf8,key_len.i,staple.p-utf8,staple_len.i) 
  tls_config_set_ocsp_staple_mem(config,staple.p-utf8,len.i)                                                                  
  tls_config_set_ocsp_staple_file(config,staple_file.p-utf8)                                                                        
  tls_config_set_protocols(config,protocols.l)                                                                               
  tls_config_set_session_fd(config,session_fd.l)                                                                                  
  tls_config_set_verify_depth(config,verify_depth.l)                                                                              
  tls_config_prefer_ciphers_client(config)                                                                                           
  tls_config_prefer_ciphers_server(config)                                                                                           
  tls_config_insecure_noverifycert(config)                                                                                           
  tls_config_insecure_noverifyname(config)                                                                                           
  tls_config_insecure_noverifytime(config)                                                                                           
  tls_config_verify(config)                                                                                                          
  tls_config_ocsp_require_stapling(config)                                                                                           
  tls_config_verify_client(config)                                                                                                   
  tls_config_verify_client_optional(config)                                                                                          
  tls_config_clear_keys(config)                                                                                                      
  tls_config_parse_protocols(*protocols,protostr.p-utf8)                                                                           
  tls_config_set_session_id(config,session_id.p-utf8,len.i)                                                                   
  tls_config_set_session_lifetime(config,lifetime.l)                                                                              
  tls_config_add_ticket_key(config,keyrev.i,*key,keylen.i)                                                   
  tls_client()                                                                                                                                
  tls_server()                                                                                                                                
  tls_configure(ctx,config)                                                                                                 
  tls_reset(ctx)                                                                                                                     
  tls_free(ctx)                                                                                                                      
  tls_accept_fds(ctx,*cctx,fd_read.l,fd_write.l)                                                                       
  tls_accept_socket(ctx,*cctx,socket.l)                                                                                   
  tls_accept_cbs(ctx,*cctx,*read_cb.tls_read_cb,*write_cb.tls_write_cb,*cb_arg)                                      
  tls_connect(ctx,host.p-utf8,port.p-utf8)                                                                                         
  tls_connect_fds(ctx,fd_read.l,fd_write.l,servername.p-utf8)                                                                 
  tls_connect_servername(ctx,host.p-utf8,port.p-utf8,servername.p-utf8)                                                           
  tls_connect_socket(ctx,s.l,servername.p-utf8)                                                                                  
  tls_connect_cbs(ctx,*read_cb.tls_read_cb,*write_cb.tls_write_cb,*cb_arg,servername.p-utf8)                                
  tls_handshake(ctx)                                                                                                                 
  tls_read(ctx,*buf,buflen.i)                                                                                            
  tls_write(ctx,*buf,buflen.i)                                                                                          
  tls_close(ctx)                                                                                                                     
  tls_peer_cert_provided(ctx)                                                                                                        
  tls_peer_cert_contains_name(ctx,name.p-utf8)                                                                                      
  tls_peer_cert_hash(ctx)                                                                                                            
  tls_peer_cert_issuer(ctx)                                                                                                          
  tls_peer_cert_subject(ctx)                                                                                                         
  tls_peer_cert_notbefore(ctx)                                                                                                       
  tls_peer_cert_notafter(ctx)                                                                                                        
  tls_peer_cert_chain_pem(ctx,*len)                                                                                          
  tls_conn_alpn_selected(ctx)                                                                                                        
  tls_conn_cipher(ctx)                                                                                                               
  tls_conn_cipher_strength(ctx)                                                                                                      
  tls_conn_servername(ctx)                                                                                                           
  tls_conn_session_resumed(ctx)                                                                                                      
  tls_conn_version(ctx)                                                                                                              
  tls_load_file(file.p-utf8,*len,*password)                                                                                    
  tls_unload_file(*buf,len.i)                                                                                                   
  tls_ocsp_process_response(ctx,response.p-utf8,size.i)                                                                       
  tls_peer_ocsp_cert_status(ctx)                                                                                                     
  tls_peer_ocsp_crl_reason(ctx)                                                                                                      
  tls_peer_ocsp_next_update(ctx)                                                                                                     
  tls_peer_ocsp_response_status(ctx)                                                                                                 
  tls_peer_ocsp_result(ctx)                                                                                                          
  tls_peer_ocsp_revocation_time(ctx)                                                                                                 
  tls_peer_ocsp_this_update(ctx)                                                                                                     
  tls_peer_ocsp_url(ctx)                                                                                                             
EndImport

CompilerIf #PB_Compiler_IsMainFile 
  Global err.s 
  
  _EXAMPLEPATH$ = GetPathPart(ProgramFilename()) 
  
  Macro LIBTLS_NOCONTEXT_ERROR(msg) 
     err.s = msg 
     Goto error  
  EndMacro 
  
  If  tls_init()  <>  0
    LIBTLS_NOCONTEXT_ERROR("can't init tls") 
  EndIf   
    
  config = tls_config_new()
  If config = 0 
     LIBTLS_NOCONTEXT_ERROR("can't config tls") 
  EndIf  
  
  If tls_config_set_cert_file(config, _EXAMPLEPATH$ + "localhost.crt") <> 0 
		LIBTLS_NOCONTEXT_ERROR("tls_config_set_cert_file() failed " + _EXAMPLEPATH$  + "localhost.crt" );
	EndIf 

	If tls_config_set_key_file(config, _EXAMPLEPATH$+ "localhost.key") <> 0 
		LIBTLS_NOCONTEXT_ERROR("tls_config_set_key_file() failed");
	EndIf 	
	    
	error: 
	MessageRequester("libreTLS",err) 
	End 
	
CompilerEndIf   
User avatar
HeX0R
Addict
Addict
Posts: 992
Joined: Mon Sep 20, 2004 7:12 am
Location: Hell

Re: TLS Client Using LibreSSL [libtls]

Post by HeX0R »

Here is a no-brainer to add TLS to your (existing?!) application, just add it on top of your code and follow the instructions in the "Usage:" comment block.
There is a "TODO" remark in the TLS_NetworkServerEvent() procedure, I can't really test servers at the time being, maybe there is some more to do.

Client side is working flawlessly in my own application so far.

[Edit]
Server has been roughly tested and seems to work also

Code: Select all

;V 1.00


;* $OpenBSD: tls.h,v 1.58 2020/01/22 06:44:02 beck Exp $ */
;*
;* Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
;*
;* Permission To use, copy, modify, And distribute this software For any
;* purpose With Or without fee is hereby granted, provided that the above
;* copyright notice And this permission notice appear in all copies.
;*
;* THE SOFTWARE IS PROVIDED "AS IS" And THE AUTHOR DISCLAIMS ALL WARRANTIES
;* With REGARD To THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
;* MERCHANTABILITY And FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE For
;* ANY SPECIAL, DIRECT, INDIRECT, Or CONSEQUENTIAL DAMAGES Or ANY DAMAGES
;* WHATSOEVER RESULTING FROM LOSS OF USE, Data Or PROFITS, WHETHER IN AN
;* ACTION OF CONTRACT, NEGLIGENCE Or OTHER TORTIOUS ACTION, ARISING OUT OF
;* Or IN CONNECTION With THE USE Or PERFORMANCE OF THIS SOFTWARE.
;*
; Original from idle => https://www.purebasic.fr/english/viewtopic.php?p=593079#p593079




;/=============
;|
;| Usage:
;| - Include that file here on top of your (existing?!) network application.
;| - make sure a libtls-xx.dll or libtls-xx.a is in the same directory as your app
;|                                               (or set a global variable LIBTLSFILE$ to path and filename of that library BEFORE including this source)
;|   you will find compiled libraries in the dropbox account from idle, see here:
;|   https://www.purebasic.fr/english/viewtopic.php?p=593079#p593079
;|   or just compile newer versions yourself
;| - That's it!
;|   If you now want to initiate a TLS connection, use all known PB commands as usual, but:
;|   Add one of the PB_Network_TLSv1_xx constants to:
;|   OpenNetworkConnection(ServerName$, Port [, Mode  <= here
;|   e.g. OpenNetworkConnection("my.domain.com", 1234, #PB_Network_TCP | #PB_Network_IPv4 | #PB_Network_TLS_DEFAULT, ...)
;|
;|   OR
;|
;|   CreateNetworkServer(Server, Port [, Mode, <== here
;|   e.g. CreateNetworkServer(#PB_Any, 1234, #PB_Network_TCP | #PB_Network_IPv4 | #PB_Network_TLS_DEFAULT, ...)
;|   In case of a server, you would need to call Init_TLS() also most likely.
;|   Because with that procedure you can set the needed TLS certificates (cert and key file typically)
;|
;|   REMARK:
;|   SERVER FUNCTIONALITY NOT TESTED!!
;|
;/============





#TLS_API = 20200120

#TLS_PROTOCOL_TLSv1_0 = (1 << 1)
#TLS_PROTOCOL_TLSv1_1 = (1 << 2)
#TLS_PROTOCOL_TLSv1_2 = (1 << 3)
#TLS_PROTOCOL_TLSv1_3 = (1 << 4)

#TLS_PROTOCOL_TLSv1 = #TLS_PROTOCOL_TLSv1_0 | #TLS_PROTOCOL_TLSv1_1 | #TLS_PROTOCOL_TLSv1_2 | #TLS_PROTOCOL_TLSv1_3

#TLS_PROTOCOLS_ALL     = #TLS_PROTOCOL_TLSv1
#TLS_PROTOCOLS_DEFAULT = (#TLS_PROTOCOL_TLSv1_2 | #TLS_PROTOCOL_TLSv1_3)

#TLS_WANT_POLLIN  = -2
#TLS_WANT_POLLOUT = -3

;/* RFC 6960 Section 2.3 */
#TLS_OCSP_RESPONSE_SUCCESSFUL    = 0
#TLS_OCSP_RESPONSE_MALFORMED     = 1
#TLS_OCSP_RESPONSE_INTERNALERROR = 2
#TLS_OCSP_RESPONSE_TRYLATER      = 3
#TLS_OCSP_RESPONSE_SIGREQUIRED   = 4
#TLS_OCSP_RESPONSE_UNAUTHORIZED  = 5

;/* RFC 6960 Section 2.2 */
#TLS_OCSP_CERT_GOOD    = 0
#TLS_OCSP_CERT_REVOKED = 1
#TLS_OCSP_CERT_UNKNOWN = 2

;/* RFC 5280 Section 5.3.1 */
#TLS_CRL_REASON_UNSPECIFIED            = 0
#TLS_CRL_REASON_KEY_COMPROMISE         = 1
#TLS_CRL_REASON_CA_COMPROMISE          = 2
#TLS_CRL_REASON_AFFILIATION_CHANGED    = 3
#TLS_CRL_REASON_SUPERSEDED             = 4
#TLS_CRL_REASON_CESSATION_OF_OPERATION = 5
#TLS_CRL_REASON_CERTIFICATE_HOLD       = 6
#TLS_CRL_REASON_REMOVE_FROM_CRL        = 8
#TLS_CRL_REASON_PRIVILEGE_WITHDRAWN    = 9
#TLS_CRL_REASON_AA_COMPROMISE          = 10

#TLS_MAX_SESSION_ID_LENGTH = 32
#TLS_TICKET_KEY_SIZE       = 48

CompilerIf Defined(PB_Network_TLSv1, #PB_Constant) = 0
	#PB_Network_TLSv1_0     = $10
	#PB_Network_TLSv1_1     = $20
	#PB_Network_TLSv1_2     = $40
	#PB_Network_TLSv1_3     = $80
	#PB_Network_TLSv1       = #PB_Network_TLSv1_0 | #PB_Network_TLSv1_1 | #PB_Network_TLSv1_2 | #PB_Network_TLSv1_3
	#PB_Network_TLS_DEFAULT = #PB_Network_TLSv1_2 | #PB_Network_TLSv1_3
	#PB_Network_KeepAlive   = $1000
	#PB_Network_Extra       = #PB_Network_TLSv1 | #PB_Network_KeepAlive
CompilerEndIf

CompilerIf Defined(TLS_AUTOINIT, #PB_Constant) = #False
	#TLS_AUTOINIT = #True
CompilerEndIf

;download build from bsd
;https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.5.0.tar.gz

;Build tools required for windows builds cmake and mingw64
;cmake
;https://cmake.org/download/

;mingw64
;Info https://www.mingw-w64.org/downloads/#llvm-mingw
;Available versions info https://github.com/mstorsjo/llvm-mingw/releases
;Direct download link https://github.com/mstorsjo/llvm-mingw/releases/download/20211002/llvm-mingw-20211002-msvcrt-x86_64.zip

;building on windows linux osx
;copy the tar file to a folder of your choice, make a subfolder and then extract the tar and cd into the folder
;> mkdir libressl-3.5.0
;> tar -xf libressl-3.5.0.tar.gz
;> cd libressl-3.5.0

;add cmake and mingw to the PATH environment variable
;(temp. for the open command console: SET PATH=%PATH%;path\to\cmake\bin\;path\to\mingw\bin\)

;Edit the file libressl-3.5.0\cmakelists and insert option(BUILD_SHARED_LIBS "Build shared" ON) at line 38
;option(BUILD_SHARED_LIBS "Build shared" ON)

;now make a build folder cd to it and call cmake
;libressl-3.5.0> mkdir build
;libressl-3.5.0> cd build

;If OS = Windows
;  libressl-3.5.0\build> cmake -S="../" -G="MinGW Makefiles"
;  libressl-3.5.0\build> mingw32-make all
;Else
;  libressl-3.5.0\build> cmake all
;  libressl-3.5.0\build> make all
;EndIf

;{ Prototypes
PrototypeC tls_read_cb(ctx, *buf, _buflen, *cb_arg)
PrototypeC tls_write_cb(ctx, *buf, _buflen, *cb_arg)

PrototypeC P_tls_init() : Global tls_init.P_tls_init
PrototypeC P_tls_config_error(config) : Global tls_config_error.P_tls_config_error
PrototypeC P_tls_error(ctx) : Global tls_error.P_tls_error
PrototypeC P_tls_config_new() : Global tls_config_new.P_tls_config_new
PrototypeC P_tls_config_free(config) : Global tls_config_free.P_tls_config_free
PrototypeC P_tls_default_ca_cert_file() : Global tls_default_ca_cert_file.P_tls_default_ca_cert_file
PrototypeC P_tls_config_add_keypair_file(config, cert_file.p-utf8, key_file.p-utf8) : Global tls_config_add_keypair_file.P_tls_config_add_keypair_file
PrototypeC P_tls_config_add_keypair_mem(config, cert.p-utf8, certlen.i, key.p-utf8, key_len.i) : Global tls_config_add_keypair_mem.P_tls_config_add_keypair_mem
PrototypeC P_tls_config_add_keypair_ocsp_file(config, cert_file.p-utf8, key_file.p-utf8, ocsp_staple_file.p-utf8) : Global tls_config_add_keypair_ocsp_file.P_tls_config_add_keypair_ocsp_file
PrototypeC P_tls_config_add_keypair_ocsp_mem(config, cert.p-utf8, cert_len.i, key.p-utf8, key_len.i, staple.p-utf8, staple_len.i) : Global tls_config_add_keypair_ocsp_mem.P_tls_config_add_keypair_ocsp_mem
PrototypeC P_tls_config_set_alpn(config, alpn.p-utf8) : Global tls_config_set_alpn.P_tls_config_set_alpn
PrototypeC P_tls_config_set_ca_file(config, ca_file.p-utf8) : Global tls_config_set_ca_file.P_tls_config_set_ca_file
PrototypeC P_tls_config_set_ca_path(config, ca_path.p-utf8) : Global tls_config_set_ca_path.P_tls_config_set_ca_path
PrototypeC P_tls_config_set_ca_mem(config, *ca, len.i) : Global tls_config_set_ca_mem.P_tls_config_set_ca_mem
PrototypeC P_tls_config_set_cert_file(config, cert_file.p-utf8) : Global tls_config_set_cert_file.P_tls_config_set_cert_file
PrototypeC P_tls_config_set_cert_mem(config, *cert, len.i) : Global tls_config_set_cert_mem.P_tls_config_set_cert_mem
PrototypeC P_tls_config_set_ciphers(config, ciphers.p-utf8) : Global tls_config_set_ciphers.P_tls_config_set_ciphers
PrototypeC P_tls_config_set_crl_file(config, crl_file.p-utf8) : Global tls_config_set_crl_file.P_tls_config_set_crl_file
PrototypeC P_tls_config_set_crl_mem(config, crl.p-utf8, len.i) : Global tls_config_set_crl_mem.P_tls_config_set_crl_mem
PrototypeC P_tls_config_set_dheparams(config, params.p-utf8) : Global tls_config_set_dheparams.P_tls_config_set_dheparams
PrototypeC P_tls_config_set_ecdhecurve(config, curve.p-utf8) : Global tls_config_set_ecdhecurve.P_tls_config_set_ecdhecurve
PrototypeC P_tls_config_set_ecdhecurves(config, curves.p-utf8) : Global tls_config_set_ecdhecurves.P_tls_config_set_ecdhecurves
PrototypeC P_tls_config_set_key_file(config, key_file.p-utf8) : Global tls_config_set_key_file.P_tls_config_set_key_file
PrototypeC P_tls_config_set_key_mem(config, *key, len.i) : Global tls_config_set_key_mem.P_tls_config_set_key_mem
PrototypeC P_tls_config_set_keypair_file(config, cert_file.p-utf8, key_file.p-utf8) : Global tls_config_set_keypair_file.P_tls_config_set_keypair_file
PrototypeC P_tls_config_set_keypair_mem(config, cert.p-utf8, cert_len.i, key.p-utf8, key_len.i) : Global tls_config_set_keypair_mem.P_tls_config_set_keypair_mem
PrototypeC P_tls_config_set_keypair_ocsp_file(config, cert_file.p-utf8, key_file.p-utf8, staple_file.p-utf8) : Global tls_config_set_keypair_ocsp_file.P_tls_config_set_keypair_ocsp_file
PrototypeC P_tls_config_set_keypair_ocsp_mem(config, cert.p-utf8, cert_len.i, key.p-utf8, key_len.i, staple.p-utf8, staple_len.i) : Global tls_config_set_keypair_ocsp_mem.P_tls_config_set_keypair_ocsp_mem
PrototypeC P_tls_config_set_ocsp_staple_mem(config, staple.p-utf8, len.i) : Global tls_config_set_ocsp_staple_mem.P_tls_config_set_ocsp_staple_mem
PrototypeC P_tls_config_set_ocsp_staple_file(config, staple_file.p-utf8) : Global tls_config_set_ocsp_staple_file.P_tls_config_set_ocsp_staple_file
PrototypeC P_tls_config_set_protocols(config, protocols.l) : Global tls_config_set_protocols.P_tls_config_set_protocols
PrototypeC P_tls_config_set_session_fd(config, session_fd.l) : Global tls_config_set_session_fd.P_tls_config_set_session_fd
PrototypeC P_tls_config_set_verify_depth(config, verify_depth.l) : Global tls_config_set_verify_depth.P_tls_config_set_verify_depth
PrototypeC P_tls_config_prefer_ciphers_client(config) : Global tls_config_prefer_ciphers_client.P_tls_config_prefer_ciphers_client
PrototypeC P_tls_config_prefer_ciphers_server(config) : Global tls_config_prefer_ciphers_server.P_tls_config_prefer_ciphers_server
PrototypeC P_tls_config_insecure_noverifycert(config) : Global tls_config_insecure_noverifycert.P_tls_config_insecure_noverifycert
PrototypeC P_tls_config_insecure_noverifyname(config) : Global tls_config_insecure_noverifyname.P_tls_config_insecure_noverifyname
PrototypeC P_tls_config_insecure_noverifytime(config) : Global tls_config_insecure_noverifytime.P_tls_config_insecure_noverifytime
PrototypeC P_tls_config_verify(config) : Global tls_config_verify.P_tls_config_verify
PrototypeC P_tls_config_ocsp_require_stapling(config) : Global tls_config_ocsp_require_stapling.P_tls_config_ocsp_require_stapling
PrototypeC P_tls_config_verify_client(config) : Global tls_config_verify_client.P_tls_config_verify_client
PrototypeC P_tls_config_verify_client_optional(config) : Global tls_config_verify_client_optional.P_tls_config_verify_client_optional
PrototypeC P_tls_config_clear_keys(config) : Global tls_config_clear_keys.P_tls_config_clear_keys
PrototypeC P_tls_config_parse_protocols(*protocols, protostr.p-utf8) : Global tls_config_parse_protocols.P_tls_config_parse_protocols
PrototypeC P_tls_config_set_session_id(config, session_id.p-utf8, len.i) : Global tls_config_set_session_id.P_tls_config_set_session_id
PrototypeC P_tls_config_set_session_lifetime(config, lifetime.l) : Global tls_config_set_session_lifetime.P_tls_config_set_session_lifetime
PrototypeC P_tls_config_add_ticket_key(config, keyrev.i, *key, keylen.i) : Global tls_config_add_ticket_key.P_tls_config_add_ticket_key
PrototypeC P_tls_client() : Global tls_client.P_tls_client
PrototypeC P_tls_server() : Global tls_server.P_tls_server
PrototypeC P_tls_configure(ctx, config) : Global tls_configure.P_tls_configure
PrototypeC P_tls_reset(ctx) : Global tls_reset.P_tls_reset
PrototypeC P_tls_free(ctx) : Global tls_free.P_tls_free
PrototypeC P_tls_accept_fds(ctx, *cctx, fd_read.l, fd_write.l) : Global tls_accept_fds.P_tls_accept_fds
PrototypeC P_tls_accept_socket(ctx, *cctx, socket.l) : Global tls_accept_socket.P_tls_accept_socket
PrototypeC P_tls_accept_cbs(ctx, *cctx, *read_cb.tls_read_cb, *write_cb.tls_write_cb, *cb_arg) : Global tls_accept_cbs.P_tls_accept_cbs
PrototypeC P_tls_connect(ctx, host.p-utf8, port.p-utf8) : Global tls_connect.P_tls_connect
PrototypeC P_tls_connect_fds(ctx, fd_read.l, fd_write.l, servername.p-utf8) : Global tls_connect_fds.P_tls_connect_fds
PrototypeC P_tls_connect_servername(ctx, host.p-utf8, port.p-utf8, servername.p-utf8) : Global tls_connect_servername.P_tls_connect_servername
PrototypeC P_tls_connect_socket(ctx, s.l, servername.p-utf8) : Global tls_connect_socket.P_tls_connect_socket
PrototypeC P_tls_connect_cbs(ctx, *read_cb.tls_read_cb, *write_cb.tls_write_cb, *cb_arg, servername.p-utf8) : Global tls_connect_cbs.P_tls_connect_cbs
PrototypeC P_tls_handshake(ctx) : Global tls_handshake.P_tls_handshake
PrototypeC P_tls_read(ctx, *buf, buflen.i) : Global tls_read.P_tls_read
PrototypeC P_tls_write(ctx, *buf, buflen.i) : Global tls_write.P_tls_write
PrototypeC P_tls_close(ctx) : Global tls_close.P_tls_close
PrototypeC P_tls_peer_cert_provided(ctx) : Global tls_peer_cert_provided.P_tls_peer_cert_provided
PrototypeC P_tls_peer_cert_contains_name(ctx, name.p-utf8) : Global tls_peer_cert_contains_name.P_tls_peer_cert_contains_name
PrototypeC P_tls_peer_cert_hash(ctx) : Global tls_peer_cert_hash.P_tls_peer_cert_hash
PrototypeC P_tls_peer_cert_issuer(ctx) : Global tls_peer_cert_issuer.P_tls_peer_cert_issuer
PrototypeC P_tls_peer_cert_subject(ctx) : Global tls_peer_cert_subject.P_tls_peer_cert_subject
PrototypeC P_tls_peer_cert_notbefore(ctx) : Global tls_peer_cert_notbefore.P_tls_peer_cert_notbefore
PrototypeC P_tls_peer_cert_notafter(ctx) : Global tls_peer_cert_notafter.P_tls_peer_cert_notafter
PrototypeC P_tls_peer_cert_chain_pem(ctx, *len) : Global tls_peer_cert_chain_pem.P_tls_peer_cert_chain_pem
PrototypeC P_tls_conn_alpn_selected(ctx) : Global tls_conn_alpn_selected.P_tls_conn_alpn_selected
PrototypeC P_tls_conn_cipher(ctx) : Global tls_conn_cipher.P_tls_conn_cipher
PrototypeC P_tls_conn_cipher_strength(ctx) : Global tls_conn_cipher_strength.P_tls_conn_cipher_strength
PrototypeC P_tls_conn_servername(ctx) : Global tls_conn_servername.P_tls_conn_servername
PrototypeC P_tls_conn_session_resumed(ctx) : Global tls_conn_session_resumed.P_tls_conn_session_resumed
PrototypeC P_tls_conn_version(ctx) : Global tls_conn_version.P_tls_conn_version
PrototypeC P_tls_load_file(file.p-utf8, *len, *password) : Global tls_load_file.P_tls_load_file
PrototypeC P_tls_unload_file(*buf, len.i) : Global tls_unload_file.P_tls_unload_file
PrototypeC P_tls_ocsp_process_response(ctx, response.p-utf8, size.i) : Global tls_ocsp_process_response.P_tls_ocsp_process_response
PrototypeC P_tls_peer_ocsp_cert_status(ctx) : Global tls_peer_ocsp_cert_status.P_tls_peer_ocsp_cert_status
PrototypeC P_tls_peer_ocsp_crl_reason(ctx) : Global tls_peer_ocsp_crl_reason.P_tls_peer_ocsp_crl_reason
PrototypeC P_tls_peer_ocsp_next_update(ctx) : Global tls_peer_ocsp_next_update.P_tls_peer_ocsp_next_update
PrototypeC P_tls_peer_ocsp_response_status(ctx) : Global tls_peer_ocsp_response_status.P_tls_peer_ocsp_response_status
PrototypeC P_tls_peer_ocsp_result(ctx) : Global tls_peer_ocsp_result.P_tls_peer_ocsp_result
PrototypeC P_tls_peer_ocsp_revocation_time(ctx) : Global tls_peer_ocsp_revocation_time.P_tls_peer_ocsp_revocation_time
PrototypeC P_tls_peer_ocsp_this_update(ctx) : Global tls_peer_ocsp_this_update.P_tls_peer_ocsp_this_update
PrototypeC P_tls_peer_ocsp_url(ctx) : Global tls_peer_ocsp_url.P_tls_peer_ocsp_url
;}

Structure TLS_Connections
	*ctx
EndStructure

Structure TLS_Globals
	CertFile$
	KeyFile$
	CaCertFile$
	LastError.i
	DLL.i
	Map Clients.TLS_Connections()
	Map Servers.TLS_Connections()
EndStructure

Global TLSG.TLS_Globals

Procedure __MyInit()
	CompilerIf Defined(LIBTLSFILE$, #PB_Variable)
		TLSG\DLL = OpenLibrary(#PB_Any, LIBTLSFILE$)
	CompilerElse
		CompilerSelect #PB_Compiler_OS
			CompilerCase #PB_OS_Windows
				TLSG\DLL = OpenLibrary(#PB_Any, "libtls-26.dll")
				;error? get it from https://www.purebasic.fr/english/viewtopic.php?p=593079#p593079
			CompilerDefault
				TLSG\DLL = OpenLibrary(#PB_Any, "libtls.a")
				;error? get it from https://www.purebasic.fr/english/viewtopic.php?p=593079#p593079
		CompilerEndSelect
	CompilerEndIf
	
	If TLSG\DLL
		tls_init                          = GetFunction(TLSG\DLL, "tls_init")
		tls_config_error                  = GetFunction(TLSG\DLL, "tls_config_error")
		tls_error                         = GetFunction(TLSG\DLL, "tls_error")
		tls_config_new                    = GetFunction(TLSG\DLL, "tls_config_new")
		tls_config_free                   = GetFunction(TLSG\DLL, "tls_config_free")
		tls_default_ca_cert_file          = GetFunction(TLSG\DLL, "tls_default_ca_cert_file")
		tls_config_add_keypair_file       = GetFunction(TLSG\DLL, "tls_config_add_keypair_file")
		tls_config_add_keypair_mem        = GetFunction(TLSG\DLL, "tls_config_add_keypair_mem")
		tls_config_add_keypair_ocsp_file  = GetFunction(TLSG\DLL, "tls_config_add_keypair_ocsp_file")
		tls_config_add_keypair_ocsp_mem   = GetFunction(TLSG\DLL, "tls_config_add_keypair_ocsp_mem")
		tls_config_set_alpn               = GetFunction(TLSG\DLL, "tls_config_set_alpn")
		tls_config_set_ca_file            = GetFunction(TLSG\DLL, "tls_config_set_ca_file")
		tls_config_set_ca_path            = GetFunction(TLSG\DLL, "tls_config_set_ca_path")
		tls_config_set_ca_mem             = GetFunction(TLSG\DLL, "tls_config_set_ca_mem")
		tls_config_set_cert_file          = GetFunction(TLSG\DLL, "tls_config_set_cert_file")
		tls_config_set_cert_mem           = GetFunction(TLSG\DLL, "tls_config_set_cert_mem")
		tls_config_set_ciphers            = GetFunction(TLSG\DLL, "tls_config_set_ciphers")
		tls_config_set_crl_file           = GetFunction(TLSG\DLL, "tls_config_set_crl_file")
		tls_config_set_crl_mem            = GetFunction(TLSG\DLL, "tls_config_set_crl_mem")
		tls_config_set_dheparams          = GetFunction(TLSG\DLL, "tls_config_set_dheparams")
		tls_config_set_ecdhecurve         = GetFunction(TLSG\DLL, "tls_config_set_ecdhecurve")
		tls_config_set_ecdhecurves        = GetFunction(TLSG\DLL, "tls_config_set_ecdhecurves")
		tls_config_set_key_file           = GetFunction(TLSG\DLL, "tls_config_set_key_file")
		tls_config_set_key_mem            = GetFunction(TLSG\DLL, "tls_config_set_key_mem")
		tls_config_set_keypair_file       = GetFunction(TLSG\DLL, "tls_config_set_keypair_file")
		tls_config_set_keypair_mem        = GetFunction(TLSG\DLL, "tls_config_set_keypair_mem")
		tls_config_set_keypair_ocsp_file  = GetFunction(TLSG\DLL, "tls_config_set_keypair_ocsp_file")
		tls_config_set_keypair_ocsp_mem   = GetFunction(TLSG\DLL, "tls_config_set_keypair_ocsp_mem")
		tls_config_set_ocsp_staple_mem    = GetFunction(TLSG\DLL, "tls_config_set_ocsp_staple_mem")
		tls_config_set_ocsp_staple_file   = GetFunction(TLSG\DLL, "tls_config_set_ocsp_staple_file")
		tls_config_set_protocols          = GetFunction(TLSG\DLL, "tls_config_set_protocols")
		tls_config_set_session_fd         = GetFunction(TLSG\DLL, "tls_config_set_session_fd")
		tls_config_set_verify_depth       = GetFunction(TLSG\DLL, "tls_config_set_verify_depth")
		tls_config_prefer_ciphers_client  = GetFunction(TLSG\DLL, "tls_config_prefer_ciphers_client")
		tls_config_prefer_ciphers_server  = GetFunction(TLSG\DLL, "tls_config_prefer_ciphers_server")
		tls_config_insecure_noverifycert  = GetFunction(TLSG\DLL, "tls_config_insecure_noverifycert")
		tls_config_insecure_noverifyname  = GetFunction(TLSG\DLL, "tls_config_insecure_noverifyname")
		tls_config_insecure_noverifytime  = GetFunction(TLSG\DLL, "tls_config_insecure_noverifytime")
		tls_config_verify                 = GetFunction(TLSG\DLL, "tls_config_verify")
		tls_config_ocsp_require_stapling  = GetFunction(TLSG\DLL, "tls_config_ocsp_require_stapling")
		tls_config_verify_client          = GetFunction(TLSG\DLL, "tls_config_verify_client")
		tls_config_verify_client_optional = GetFunction(TLSG\DLL, "tls_config_verify_client_optional")
		tls_config_clear_keys             = GetFunction(TLSG\DLL, "tls_config_clear_keys")
		tls_config_parse_protocols        = GetFunction(TLSG\DLL, "tls_config_parse_protocols")
		tls_config_set_session_id         = GetFunction(TLSG\DLL, "tls_config_set_session_id")
		tls_config_set_session_lifetime   = GetFunction(TLSG\DLL, "tls_config_set_session_lifetime")
		tls_config_add_ticket_key         = GetFunction(TLSG\DLL, "tls_config_add_ticket_key")
		tls_client                        = GetFunction(TLSG\DLL, "tls_client")
		tls_server                        = GetFunction(TLSG\DLL, "tls_server")
		tls_configure                     = GetFunction(TLSG\DLL, "tls_configure")
		tls_reset                         = GetFunction(TLSG\DLL, "tls_reset")
		tls_free                          = GetFunction(TLSG\DLL, "tls_free")
		tls_accept_fds                    = GetFunction(TLSG\DLL, "tls_accept_fds")
		tls_accept_socket                 = GetFunction(TLSG\DLL, "tls_accept_socket")
		tls_accept_cbs                    = GetFunction(TLSG\DLL, "tls_accept_cbs")
		tls_connect                       = GetFunction(TLSG\DLL, "tls_connect")
		tls_connect_fds                   = GetFunction(TLSG\DLL, "tls_connect_fds")
		tls_connect_servername            = GetFunction(TLSG\DLL, "tls_connect_servername")
		tls_connect_socket                = GetFunction(TLSG\DLL, "tls_connect_socket")
		tls_connect_cbs                   = GetFunction(TLSG\DLL, "tls_connect_cbs")
		tls_handshake                     = GetFunction(TLSG\DLL, "tls_handshake")
		tls_read                          = GetFunction(TLSG\DLL, "tls_read")
		tls_write                         = GetFunction(TLSG\DLL, "tls_write")
		tls_close                         = GetFunction(TLSG\DLL, "tls_close")
		tls_peer_cert_provided            = GetFunction(TLSG\DLL, "tls_peer_cert_provided")
		tls_peer_cert_contains_name       = GetFunction(TLSG\DLL, "tls_peer_cert_contains_name")
		tls_peer_cert_hash                = GetFunction(TLSG\DLL, "tls_peer_cert_hash")
		tls_peer_cert_issuer              = GetFunction(TLSG\DLL, "tls_peer_cert_issuer")
		tls_peer_cert_subject             = GetFunction(TLSG\DLL, "tls_peer_cert_subject")
		tls_peer_cert_notbefore           = GetFunction(TLSG\DLL, "tls_peer_cert_notbefore")
		tls_peer_cert_notafter            = GetFunction(TLSG\DLL, "tls_peer_cert_notafter")
		tls_peer_cert_chain_pem           = GetFunction(TLSG\DLL, "tls_peer_cert_chain_pem")
		tls_conn_alpn_selected            = GetFunction(TLSG\DLL, "tls_conn_alpn_selected")
		tls_conn_cipher                   = GetFunction(TLSG\DLL, "tls_conn_cipher")
		tls_conn_cipher_strength          = GetFunction(TLSG\DLL, "tls_conn_cipher_strength")
		tls_conn_servername               = GetFunction(TLSG\DLL, "tls_conn_servername")
		tls_conn_session_resumed          = GetFunction(TLSG\DLL, "tls_conn_session_resumed")
		tls_conn_version                  = GetFunction(TLSG\DLL, "tls_conn_version")
		tls_load_file                     = GetFunction(TLSG\DLL, "tls_load_file")
		tls_unload_file                   = GetFunction(TLSG\DLL, "tls_unload_file")
		tls_ocsp_process_response         = GetFunction(TLSG\DLL, "tls_ocsp_process_response")
		tls_peer_ocsp_cert_status         = GetFunction(TLSG\DLL, "tls_peer_ocsp_cert_status")
		tls_peer_ocsp_crl_reason          = GetFunction(TLSG\DLL, "tls_peer_ocsp_crl_reason")
		tls_peer_ocsp_next_update         = GetFunction(TLSG\DLL, "tls_peer_ocsp_next_update")
		tls_peer_ocsp_response_status     = GetFunction(TLSG\DLL, "tls_peer_ocsp_response_status")
		tls_peer_ocsp_result              = GetFunction(TLSG\DLL, "tls_peer_ocsp_result")
		tls_peer_ocsp_revocation_time     = GetFunction(TLSG\DLL, "tls_peer_ocsp_revocation_time")
		tls_peer_ocsp_this_update         = GetFunction(TLSG\DLL, "tls_peer_ocsp_this_update")
		tls_peer_ocsp_url                 = GetFunction(TLSG\DLL, "tls_peer_ocsp_url")
	EndIf
	
	ProcedureReturn TLSG\DLL
EndProcedure

Enumeration TLS_Errors
	#TLS_Error_None
	#TLS_Error_InitFailed
	#TLS_Error_NewConfig_Failed
	#TLS_Error_CantLoad_CertFile
	#TLS_Error_CantLoad_KeyFile
	#TLS_Error_CantLoad_RootCert
	#TLS_Error_Unsupported_Protocol
	#TLS_Error_Cant_Start_Client
	#TLS_Error_Configure_Error
	#TLS_Error_Cant_Start_Server
	#TLS_Error_Cant_Connect_Socket
EndEnumeration


Global TLSG\LastError = #TLS_Error_None

Procedure TLS_GetLastError()
	ProcedureReturn TLSG\LastError
EndProcedure

Procedure TLS_CreateNetworkServer(Server, Port, Mode, BindedIP.s)
	Protected TLSMode, ServerID, *ctx, *cfg, *Error, SockOpt.l, SockOptLen.l
	
	If TLSG\DLL And Mode & #PB_Network_TLSv1
		TLSMode = (Mode & #PB_Network_TLSv1) >> 3
		*cfg    = tls_config_new()
		If *cfg = 0
			TLSG\LastError = #TLS_Error_NewConfig_Failed
		Else
			If TLSG\CertFile$ = "" And TLSG\KeyFile$ = "" And TLSG\CaCertFile$ = ""
				tls_config_insecure_noverifycert(*cfg)
				tls_config_insecure_noverifyname(*cfg)
			Else
				If TLSG\CertFile$
					If tls_config_set_cert_file(*cfg, TLSG\CertFile$) = -1
						TLSG\LastError = #TLS_Error_CantLoad_CertFile
					EndIf
				EndIf
				If TLSG\KeyFile$
					If tls_config_set_key_file(*cfg, TLSG\KeyFile$) = -1
						TLSG\LastError = #TLS_Error_CantLoad_KeyFile
					EndIf
				EndIf
				If TLSG\CaCertFile$
					If tls_config_set_ca_file(*cfg, TLSG\CaCertFile$) = -1
						TLSG\LastError = #TLS_Error_CantLoad_RootCert
					EndIf
				EndIf
			EndIf
			If tls_config_set_protocols(*cfg, TLSMode) = -1
				TLSG\LastError = #TLS_Error_Unsupported_Protocol
			EndIf
			*ctx = tls_server()
			If *ctx = 0
				TLSG\LastError = #TLS_Error_Cant_Start_Server
			ElseIf tls_configure(*ctx, *cfg) = -1
				TLSG\LastError = #TLS_Error_Configure_Error
			Else
				*Error = tls_config_error(*cfg)
				If *Error
					Debug "TLS Config error: " + PeekS(*Error, - 1, #PB_UTF8)
				EndIf
				tls_config_free(*cfg)
				Mode     = Mode & ($FFFFFFFF - #PB_Network_Extra)
				ServerID = CreateNetworkServer(Server, Port, Mode, BindedIP)
				If ServerID
					If tls_connect_socket(*ctx, ServerID(ServerID), "someservername") = -1
						TLSG\LastError = #TLS_Error_Cant_Connect_Socket
					Else
						AddMapElement(TLSG\Servers(), Str(ServerID(ServerID)))
						TLSG\Servers()\ctx = *ctx
					EndIf
				EndIf
			EndIf
		EndIf
	Else
		ServerID = CreateNetworkServer(Server, Port, Mode, BindedIP)
	EndIf
	
	ProcedureReturn ServerID
EndProcedure

Procedure TLS_NetworkServerEvent(ServerID)
	Protected Result, Server, ClientID, ctx
	
	Result = NetworkServerEvent(ServerID)
	Select Result
		Case #PB_NetworkEvent_Connect
			Server = EventServer()
			Server = ServerID(Server)
			If FindMapElement(TLSG\Servers(), Str(Server))
				;TLS!
				ClientID = EventClient()
				If tls_accept_socket(TLSG\Servers()\ctx, @ctx, ConnectionID(ClientID)) = -1
					CloseNetworkConnection(ClientID)
					Result = #PB_NetworkEvent_None
				Else
					TLSG\Clients(Str(ClientID))\ctx = ctx
					tls_handshake(ctx)
					;TODO not sure if that will do, or if there is more to do
				EndIf
			EndIf
		Case #PB_NetworkEvent_Disconnect
			Server = EventServer()
			Server = ServerID(Server)
			If FindMapElement(TLSG\Servers(), Str(Server))
				;TLS!
				ClientID = EventClient()
				If FindMapElement(TLSG\Clients(), Str(ClientID))
					tls_close(TLSG\Clients()\ctx)
					tls_free(TLSG\Clients()\ctx)
					DeleteMapElement(TLSG\Clients())
				EndIf
			EndIf
	EndSelect
	
	ProcedureReturn Result
EndProcedure

Procedure TLS_CloseNetworkServer(Server)
	If FindMapElement(TLSG\Clients(), Str(Server))
    ;is TLS connection!
		CloseNetworkServer(Server)
		tls_close(TLSG\Clients()\ctx)
		tls_free(TLSG\Clients()\ctx)
		DeleteMapElement(TLSG\Clients())
	Else
		CloseNetworkServer(Server)
	EndIf
	
EndProcedure


Procedure TLS_OpenNetworkConnection(ServerName$, Port, Mode, TimeOut, LocaleIP$, LocalePort)
	Protected TLSMode, ClientID, *ctx, *cfg, *Error, SockOpt.l, SockOptLen.l
	
	If Mode & #PB_Network_TLSv1
		TLSMode = (Mode & #PB_Network_TLSv1) >> 3
		Mode    = Mode & ($FFFFFFFF - #PB_Network_Extra)
	EndIf
	
	If TLSG\DLL And TLSMode
		*cfg = tls_config_new()
		If *cfg = 0
			TLSG\LastError = #TLS_Error_NewConfig_Failed
		Else
			If TLSG\CertFile$ = "" And TLSG\KeyFile$ = "" And TLSG\CaCertFile$ = ""
				tls_config_insecure_noverifycert(*cfg)
				tls_config_insecure_noverifyname(*cfg)
			Else
				If TLSG\CertFile$
					If tls_config_set_cert_file(*cfg, TLSG\CertFile$) = -1
						TLSG\LastError = #TLS_Error_CantLoad_CertFile
					EndIf
				EndIf
				If TLSG\KeyFile$
					If tls_config_set_key_file(*cfg, TLSG\KeyFile$) = -1
						TLSG\LastError = #TLS_Error_CantLoad_KeyFile
					EndIf
				EndIf
				If TLSG\CaCertFile$
					If tls_config_set_ca_file(*cfg, TLSG\CaCertFile$) = -1
						TLSG\LastError = #TLS_Error_CantLoad_RootCert
					EndIf
				EndIf
			EndIf
			If tls_config_set_protocols(*cfg, TLSMode) = -1
				TLSG\LastError = #TLS_Error_Unsupported_Protocol
			EndIf
			*ctx = tls_client()
			If *ctx = 0
				TLSG\LastError = #TLS_Error_Cant_Start_Client
			ElseIf tls_configure(*ctx, *cfg) = -1
				TLSG\LastError = #TLS_Error_Configure_Error
			Else
				*Error = tls_config_error(*cfg)
				If *Error
					Debug "TLS Config error: " + PeekS(*Error, - 1, #PB_UTF8)
				EndIf
				tls_config_free(*cfg)
				ClientID = OpenNetworkConnection(ServerName$, Port, Mode, TimeOut, LocaleIP$, LocalePort)
				If ClientID
					tls_connect_socket(*ctx, ConnectionID(ClientID), ServerName$)
					
;           *Error = tls_conn_version(*ctx) : If *Error : Debug "Version: " + PeekS(*Error, -1, #PB_UTF8) : EndIf
;           *Error = tls_conn_cipher(*ctx)  : If *Error : Debug "Cipher: " + PeekS(*Error, -1, #PB_UTF8) : EndIf
;           *Error = tls_conn_servername(*ctx) : If *Error : Debug "Servername: " + PeekS(*Error, -1, #PB_UTF8) : EndIf
;           If tls_peer_cert_provided(*ctx) : Debug "Cert Provided!" : Else : Debug "No Cert provided!" : EndIf
;           *Error = tls_peer_cert_subject(*ctx) : If *Error : Debug "Cert Subject: " + PeekS(*Error, -1, #PB_UTF8) : EndIf
;           *Error = tls_peer_cert_issuer(*ctx) : If *Error : Debug "Cert Issuer: " + PeekS(*Error, -1, #PB_UTF8) : EndIf
					
					AddMapElement(TLSG\Clients(), Str(ClientID))
					TLSG\Clients()\ctx = *ctx
				EndIf
			EndIf
		EndIf
	Else
		ClientID = OpenNetworkConnection(ServerName$, Port, Mode, TimeOut, LocaleIP$, LocalePort)
	EndIf
	
	ProcedureReturn ClientID
EndProcedure

Procedure TLS_ReceiveNetworkData(ClientID, Buffer, Length)
	Protected Result
	
	If FindMapElement(TLSG\Clients(), Str(ClientID))
		Result = tls_read(TLSG\Clients()\ctx, Buffer, Length)
	Else
		Result = ReceiveNetworkData(ClientID, Buffer, Length)
	EndIf
	
	ProcedureReturn Result
EndProcedure

Procedure TLS_SendNetworkData(ClientID, Buffer, Length)
	Protected Result
	
	If FindMapElement(TLSG\Clients(), Str(ClientID))
		Result = tls_write(TLSG\Clients()\ctx, Buffer, Length)
	Else
		Result = SendNetworkData(ClientID, Buffer, Length)
	EndIf
	
	ProcedureReturn Result
EndProcedure

Procedure TLS_SendNetworkString(ClientID, String$, Format)
	Protected Result, *Buffer
	
	If FindMapElement(TLSG\Clients(), Str(ClientID))
		Select Format
			Case #PB_Ascii
				*Buffer = Ascii(String$)
				Result  = tls_write(TLSG\Clients()\ctx, *Buffer, MemorySize(*Buffer) - 1)
				FreeMemory(*Buffer)
			Case #PB_Unicode
				Result = tls_write(TLSG\Clients()\ctx, @String$, StringByteLength(String$))
			Case #PB_UTF8
				*Buffer = UTF8(String$)
				Result  = tls_write(TLSG\Clients()\ctx, *Buffer, MemorySize(*Buffer) - 1)
				FreeMemory(*Buffer)
		EndSelect
	Else
		Result = SendNetworkString(ClientID, String$, Format)
	EndIf
	
	ProcedureReturn Result
EndProcedure

Procedure TLS_CloseNetworkConnection(ClientID)
	If FindMapElement(TLSG\Clients(), Str(ClientID))
    ;is TLS connection!
		CloseNetworkConnection(ClientID)
		tls_close(TLSG\Clients()\ctx)
		tls_free(TLSG\Clients()\ctx)
		DeleteMapElement(TLSG\Clients())
	Else
		CloseNetworkConnection(ClientID)
	EndIf
EndProcedure

Procedure Init_TLS(CertFile$ = "", KeyFile$ = "", CaCertFile$ = "")
  ;Only needed, when you have certificates.
  ;the library will call tls_init() internally already when needed
  ;but you can call it as often as you want (to use different certificates right before a connection e.g.)
	Protected Result
	If tls_init() = #TLS_Error_None
		TLSG\CertFile$   = CertFile$
		TLSG\KeyFile$    = KeyFile$
		TLSG\CaCertFile$ = CaCertFile$
		Result           = #True
	Else
		Result = #TLS_Error_InitFailed
	EndIf
	
	ProcedureReturn Result
EndProcedure

Macro OpenNetworkConnection(ServerName, Port, Mode = #PB_Network_TCP | #PB_Network_IPv4, TimeOut = 0, LocaleIP = "", LocalePort = 0)
	TLS_OpenNetworkConnection(ServerName, Port, Mode, TimeOut, LocaleIP, LocalePort)
EndMacro

Macro CloseNetworkConnection(ClientID)
	TLS_CloseNetworkConnection(ClientID)
EndMacro

Macro ReceiveNetworkData(ClientID, Buffer, Length)
	TLS_ReceiveNetworkData(ClientID, Buffer, Length)
EndMacro

Macro SendNetworkData(ClientID, Buffer, Length)
	TLS_SendNetworkData(ClientID, Buffer, Length)
EndMacro

Macro SendNetworkString(ClientID, String, Format = #PB_UTF8)
	TLS_SendNetworkString(ClientID, String, Format)
EndMacro

Macro CreateNetworkServer(Server, Port, Mode = #PB_Network_TCP | #PB_Network_IPv4, BindedIP = "")
	TLS_CreateNetworkServer(Server, Port, Mode, BindedIP)
EndMacro

Macro CloseNetworkServer(Server)
	TLS_CloseNetworkServer(Server)
EndMacro

Macro NetworkServerEvent(ServerID = -1)
	TLS_NetworkServerEvent(ServerID)
EndMacro



CompilerIf #TLS_AUTOINIT
	__MyInit()
CompilerEndIf

;-Demo from infratec
CompilerIf #PB_Compiler_IsMainFile
	
	Define.i Con, Timeout, Length
	Define Receive$
	Define *Buffer
	
	
	Con = OpenNetworkConnection("www.purebasic.fr", 443, #PB_Network_TCP | #PB_Network_IPv4 | #PB_Network_TLS_DEFAULT)
	If Con
		*Buffer = AllocateMemory($FFFF, #PB_Memory_NoClear)
		If *Buffer
			
			SendNetworkString(Con, "GET / HTTP/1.1" + #CRLF$ + "Host: www.purebasic.fr" + #CRLF$ + #CRLF$)
			
			Timeout = 100
			Repeat
				Select NetworkClientEvent(Con)
					Case #PB_NetworkEvent_Data
						Repeat
							Length = ReceiveNetworkData(Con, *Buffer, MemorySize(*Buffer))
							If Length > 0
								Receive$ + PeekS(*Buffer, Length, #PB_UTF8 | #PB_ByteLength)
							EndIf
						Until Length = 0 Or (Length > 0 And Length <> MemorySize(*Buffer))
						Break
						
					Case #PB_NetworkEvent_Disconnect
						Break
						
					Case #PB_NetworkEvent_None
						Delay(10)
						Timeout - 1
						
				EndSelect
			Until Timeout = 0
			
			If Receive$ <> ""
				Debug Receive$
			EndIf
			
			FreeMemory(*Buffer)
		EndIf
		
		CloseNetworkConnection(Con)
	EndIf
	
CompilerEndIf
Last edited by HeX0R on Fri Nov 17, 2023 11:00 pm, edited 1 time in total.
User avatar
skinkairewalker
Enthusiast
Enthusiast
Posts: 635
Joined: Fri Dec 04, 2015 9:26 pm

Re: TLS Networking Using LibTLS

Post by skinkairewalker »

Does anyone know how to use letsencrypt with windows example?
infratec
Always Here
Always Here
Posts: 6874
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: TLS Networking Using LibTLS

Post by infratec »

Let's encrypt only provides certificates.
You can use them with Init_TLS()
infratec
Always Here
Always Here
Posts: 6874
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: TLS Networking Using LibTLS

Post by infratec »

A small client example:
(you can add it to the pbi file)

Code: Select all

;-Demo
CompilerIf #PB_Compiler_IsMainFile
  
  Define.i Con, Timeout, Length
  Define Receive$
  Define *Buffer
  
  
  Con = OpenNetworkConnection("www.purebasic.fr", 443, #PB_Network_TCP | #PB_Network_IPv4 | #PB_Network_TLSv1)
  If Con
    *Buffer = AllocateMemory($FFFF, #PB_Memory_NoClear)
    If *Buffer
      
      SendNetworkString(Con, "GET / HTTP/1.1" + #CRLF$ + "Host: www.purebasic.fr" + #CRLF$ + #CRLF$)
      
      Timeout = 100
      Repeat
        Select NetworkClientEvent(Con)
          Case #PB_NetworkEvent_Data
            Repeat
              Length = ReceiveNetworkData(Con, *Buffer, MemorySize(*Buffer))
              If Length > 0
                Receive$ + PeekS(*Buffer, Length, #PB_UTF8|#PB_ByteLength)
              EndIf
            Until Length = 0 Or (Length > 0 And Length <> MemorySize(*Buffer))
            Break
            
          Case #PB_NetworkEvent_Disconnect
            Break
            
          Case #PB_NetworkEvent_None
            Delay(10)
            Timeout - 1
            
        EndSelect
      Until Timeout = 0
      
      If Receive$ <> ""
        Debug Receive$
      EndIf
      
      FreeMemory(*Buffer)
    EndIf
    
    CloseNetworkConnection(Con)
  EndIf
  
CompilerEndIf
The dll from idle is for x64. You need PB x64 to run it in windows.
User avatar
skinkairewalker
Enthusiast
Enthusiast
Posts: 635
Joined: Fri Dec 04, 2015 9:26 pm

Re: TLS Networking Using LibTLS

Post by skinkairewalker »

this is wonderful, thank you very much infratec !!!
I hope to reach your level someday.
User avatar
skinkairewalker
Enthusiast
Enthusiast
Posts: 635
Joined: Fri Dec 04, 2015 9:26 pm

Re: TLS Networking Using LibTLS

Post by skinkairewalker »

Is there any method to apply ssl/tls with server?
User avatar
idle
Always Here
Always Here
Posts: 5096
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: TLS Networking Using LibTLS

Post by idle »

Look at the web server code I posted 3 or 4 posts up.
infratec
Always Here
Always Here
Posts: 6874
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: TLS Networking Using LibTLS

Post by infratec »

A small server demo:

Code: Select all

;-Demo server
CompilerIf #PB_Compiler_IsMainFile
  
  Define.i Server, CLient, Exit
  Define HTTP$, Answer$
  Define *Buffer
  
  
  Init_TLS("localhost.crt", "localhost.key", "RootCA.pem")
  Server = CreateNetworkServer(#PB_Any, 443, #PB_Network_TCP | #PB_Network_IPv4 | #PB_Network_TLSv1)
  If Server
    
    *Buffer = AllocateMemory($FFFF, #PB_Memory_NoClear)
    If *Buffer
      
      Exit = #False
      Repeat
        
        Select NetworkServerEvent(Server)
          Case #PB_NetworkEvent_Connect
            
          Case #PB_NetworkEvent_Data
            Client = EventClient()
            Repeat
              Length = ReceiveNetworkData(Client, *Buffer, MemorySize(*Buffer))
              If Length > 0
                HTTP$ = PeekS(*Buffer, Length, #PB_UTF8|#PB_ByteLength)
                Debug "Received:" + #LF$ + HTTP$
                
                Answer$ = "<!DOCTYPE html><html><head><title>PB & LibreSSL</title></head><body>"
                If Left(HTTP$, 9) = "GET /exit"
                  Exit = #True
                  Answer$ + "<h1>PB LibreSSL Server is terminated</h1>"
                  Answer$ + "<br><br>"
                  Answer$ + "<a href='https://localhost'>Start page</a>"
                Else
                  Answer$ + "<h1>"
                  Answer$ + FormatDate("%yyyy.%mm.%dd %hh:%ii:%ss", Date()) + " PB LibreSSL Server is running"
                  Answer$ + "</h1>"
                  Answer$ + "<br><br>"
                  Answer$ + "<a href='https://localhost'>Reload</a>&nbsp;&nbsp;&nbsp;"
                  Answer$ + "<a href='https://localhost/exit'>Exit</a>"
                EndIf
                Answer$ + "</body></html>"
                
                HTTP$ = "HTTP/1.1 200 OK" + #CRLF$
                HTTP$ + "Content-Length: " + Str(StringByteLength(Answer$, #PB_UTF8)) + #CRLF$
                HTTP$ + #CRLF$
                HTTP$ + Answer$
                SendNetworkString(EventClient(), HTTP$)
              EndIf
            Until Length = 0 Or (Length > 0 And Length <> MemorySize(*Buffer))
            
          Case #PB_NetworkEvent_Disconnect
            Break
            
          Case #PB_NetworkEvent_None
            Delay(10)
            
        EndSelect
        
      Until Exit
      
      FreeMemory(*Buffer)
    EndIf
    
    CloseNetworkServer(Server)
  EndIf
  
CompilerEndIf
to create the certs you need openssl.


Batch file for windows:

Code: Select all

@echo off

REM https://gist.github.com/cecilemuller/9492b848eb8fe46d462abeb26656c4f8

set OpenSSLPath=c:\OpenSSL-Win32\bin\

REM Generate RootCA.pem, RootCA.key & RootCA.crt

%OpenSSLPath%openssl req -x509 -nodes -new -sha256 -days 365 -newkey rsa:2048 -keyout RootCA.key -out RootCA.pem -subj "/C=US/CN=Example-Root-CA"
%OpenSSLPath%openssl x509 -outform pem -in RootCA.pem -out RootCA.crt


REM Generate domain name certificate

echo authorityKeyIdentifier=keyid,issuer> domains.ext
echo basicConstraints=CA:FALSE>> domains.ext
echo keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment>> domains.ext
echo subjectAltName = @alt_names>> domains.ext
echo [alt_names]>> domains.ext
echo DNS.1 = localhost>> domains.ext
echo DNS.2 = fake1.local>> domains.ext
echo DNS.3 = fake2.local>> domains.ext

%OpenSSLPath%openssl req -new -nodes -newkey rsa:2048 -keyout localhost.key -out localhost.csr -subj "/C=US/ST=YourState/L=YourCity/O=Example-Certificates/CN=localhost.local"
%OpenSSLPath%openssl x509 -req -sha256 -days 1024 -in localhost.csr -CA RootCA.pem -CAkey RootCA.key -CAcreateserial -extfile domains.ext -out localhost.crt
But you still need an exception in your browser, because the cert is selfsigned :cry:
User avatar
skinkairewalker
Enthusiast
Enthusiast
Posts: 635
Joined: Fri Dec 04, 2015 9:26 pm

Re: TLS Networking Using LibTLS

Post by skinkairewalker »

I tried to take a test and didn't get a satisfactory result.
hoerbie
Enthusiast
Enthusiast
Posts: 123
Joined: Fri Dec 06, 2013 11:57 am
Location: DE/BY/MUC

Re: TLS Networking Using LibTLS

Post by hoerbie »

Thanks to Opcode, idle, HexOr and infratec for this pieces of code!

I tried it on Windows 10 x64 with PB 6.04 und PB 6.10b5 and it seems to work for a https server, although the server crashed at the first tries after the first call, but maybe there was an antivir fighting against, because after some starts the server worked for 15 minutes and until I exited it.

I would really love to have stable TLS for CreateNetworkServer() integrated in PB, so that it is usable cross platform and for Win 32, because we have a lot of systems with 32 bit Windows 10 running due to needs of other old tools. :(

Before I make an offer to Fred, maybe there are others in the PB community that would as well pay something for this and we can add the amounts? :?:
User avatar
skinkairewalker
Enthusiast
Enthusiast
Posts: 635
Joined: Fri Dec 04, 2015 9:26 pm

Re: TLS Networking Using LibTLS

Post by skinkairewalker »

for some reason if I use the x64 dlls, the browser displays the error: ERR_EMPTY_RESPONSE, but if I replace the dlls and the compiler with x86, it works normally...
Could it be that my PC is dealing poorly with x64 DLLs?

debugging the return of:

Code: Select all

 Length = ReceiveNetworkData(Client, *Buffer, MemorySize(*Buffer))
 Debug Str(Length)
I get the results -1 and -2 :

screenshots : https://prnt.sc/TuVyYYVkrzux
https://prnt.sc/2sU0wyKOYxi2

x86 works normally with the same code.


I have a question about the certificate, because the browser does not recognize it as a valid certificate?

screenshot : https://prnt.sc/20yw0kggaqga
hoerbie
Enthusiast
Enthusiast
Posts: 123
Joined: Fri Dec 06, 2013 11:57 am
Location: DE/BY/MUC

Re: TLS Networking Using LibTLS

Post by hoerbie »

Hi,

what 32-bit dlls did you use? Until now I only tried it with PB x64 on Windows 10/11 64bit with the libtls-24.dll from idles dropbox, and this worked.

A certificate that doesn't bring up warnings from a real browser needs to be signed by a trusted authority. For my web servers I use certificates signed by Sectigo, their positive ssl certs are sold for about 10 €/$ per year. Or you can get signed certificates from Let's encrypt, but from my knowledge these need to be changed after 3 month.
With self signed certificates like in the posts here you can simply tell the browser to accept a certificate, for internal use this should be sufficient. If you don't want the warnings, you normally can import the authoritative certificate that you used for signing into the browser.

Greetings, hoerbie
infratec
Always Here
Always Here
Posts: 6874
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: TLS Networking Using LibTLS

Post by infratec »

localhost can never have a 'valid' certificate.
Also an IP address can never have 'valid' certificate.

You can add an entry in your hosts file (/windows/system32/driver/etc/hosts)
like

127.0.0.1 my.domain.com

Then you can use this name in the browser line. (https://my.domain.com)
For this domain you can then use lets encrypt to build a valid certificate.
But .. this is not trivial.
An automatic renew after 3 month is not a big deal.
Post Reply