* contrib/hbssl/evp.c
* clear key and iv buffers before passing them to EVP_BytesToKey()
otherwise some uninitialized bytes are accessed and valgrind reports
uninitialized memory access
* contrib/hbssl/evpciph.c
! fixed typo in index in my previous commit
* contrib/hbssl/tests/digest.prg
! use OPENSSL_VERSION_NUMBER() instead OPENSSL_VERSION() to retrieve
OpenSSL version number
* contrib/hbssl/tests/inetssl.prg
* updated to use 2048 RSA certificates instead of 1024 ones which are
no more supported by modern OpenSSL libraries
* contrib/hbssl/tests/pem.prg
* cleaned output
203 lines
5.6 KiB
Plaintext
203 lines
5.6 KiB
Plaintext
/*
|
|
* Copyright 2015 Przemyslaw Czerpak (druzus/at/poczta.onet.pl)
|
|
*/
|
|
|
|
#require "hbssl"
|
|
|
|
#define N_PORT 4001
|
|
#define EOL e"\r\n"
|
|
#define PEM_CERT_FILE "inetssl.pem"
|
|
|
|
STATIC s_lReady := .F.
|
|
STATIC s_lStop := .F.
|
|
|
|
STATIC s_lDelaySrv := .F.
|
|
STATIC s_lDelayCli := .F.
|
|
|
|
REQUEST HB_MT
|
|
|
|
PROCEDURE Main( delay )
|
|
LOCAL thrd
|
|
|
|
IF ! Empty( delay )
|
|
s_lDelayCli := "C" $ Upper( delay )
|
|
s_lDelaySrv := "S" $ Upper( delay )
|
|
ENDIF
|
|
|
|
/* initialize SSL library */
|
|
SSL_init()
|
|
RAND_seed( Time() + hb_TSToStr( hb_DateTime() ) + hb_DirBase() + NetName() )
|
|
|
|
/* start server thread */
|
|
thrd := hb_threadStart( @Server() )
|
|
IF Empty( thrd )
|
|
? "Cannot start thread."
|
|
RETURN
|
|
ENDIF
|
|
|
|
/* wait for server being ready to accept incoming connections */
|
|
DO WHILE ! s_lReady
|
|
hb_idleSleep( 0.01 )
|
|
IF hb_threadWait( thrd, 0 ) != 0
|
|
hb_threadJoin( thrd )
|
|
QUIT
|
|
ENDIF
|
|
ENDDO
|
|
|
|
/* start client */
|
|
Client()
|
|
|
|
/* inform server it should finish and wait for it */
|
|
s_lStop := .T.
|
|
hb_threadJoin( thrd )
|
|
?
|
|
|
|
RETURN
|
|
|
|
|
|
STATIC FUNCTION Client()
|
|
LOCAL sock, ssl_ctx, ssl, nResult, nErr, cLine
|
|
|
|
ssl_ctx := SSL_CTX_new()
|
|
ssl := SSL_new( ssl_ctx )
|
|
|
|
sock := hb_inetCreate()
|
|
hb_inetTimeout( sock, 5000 )
|
|
|
|
? "CLIENT: connecting..."
|
|
IF Empty( hb_inetConnectIP( "127.0.0.1", N_PORT, sock ) )
|
|
? "CLIENT: cannot connect to server."
|
|
ELSE
|
|
? "CLIENT: connected to the server."
|
|
hb_inetTimeout( sock, 3000 )
|
|
|
|
IF s_lDelayCli
|
|
? "CLIENT: waiting..."
|
|
hb_idleSleep( 1 )
|
|
ENDIF
|
|
|
|
? "CLIENT: SSL CONNECT..."
|
|
nResult := hb_inetSSL_CONNECT( sock, ssl )
|
|
nErr := ERR_get_error()
|
|
?? hb_StrFormat( e"\nCLIENT: hb_inetSSL_CONNECT()=>%d (%d), '%s'\n", ;
|
|
nResult, nErr, ;
|
|
ERR_error_string( nErr ) )
|
|
IF nResult == 1
|
|
? "CLIENT: connected with", SSL_get_cipher( ssl ), "encryption."
|
|
DispCertInfo( ssl, "CLIENT: " )
|
|
|
|
hb_inetSendAll( sock, hb_TSToStr( hb_DateTime() ) + EOL )
|
|
DO WHILE ! Empty( cLine := hb_inetRecvLine( sock ) )
|
|
? "CLIENT: RECV:", hb_ValToExp( cLine )
|
|
ENDDO
|
|
ENDIF
|
|
ENDIF
|
|
hb_inetClose( sock )
|
|
|
|
RETURN NIL
|
|
|
|
|
|
STATIC FUNCTION Server()
|
|
LOCAL sockSrv, sockConn, ssl_ctx, ssl, nResult, nErr, cLine
|
|
|
|
? "SERVER: loading certificates..."
|
|
ssl_ctx := SSL_CTX_new()
|
|
LoadCertificates( ssl_ctx, PEM_CERT_FILE, PEM_CERT_FILE )
|
|
ssl := SSL_new( ssl_ctx )
|
|
|
|
? "SERVER: create listen socket..."
|
|
IF Empty( sockSrv := hb_inetServer( N_PORT ) )
|
|
? "SERVER: cannot create listen socket."
|
|
ELSE
|
|
|
|
? "SERVER: waiting for connections..."
|
|
hb_inetTimeout( sockSrv, 100 )
|
|
s_lReady := .T.
|
|
DO WHILE ! s_lStop
|
|
IF ! Empty( sockConn := hb_inetAccept( sockSrv ) )
|
|
? "SERVER: accepted new connection."
|
|
hb_inetTimeout( sockConn, 3000 )
|
|
|
|
IF s_lDelaySrv
|
|
? "SERVER: waiting..."
|
|
hb_idleSleep( 1 )
|
|
ENDIF
|
|
|
|
? "SERVER: SSL ACCEPT..."
|
|
nResult := hb_inetSSL_ACCEPT( sockConn, ssl )
|
|
nErr := ERR_get_error()
|
|
?? hb_StrFormat( e"\nSERVER: hb_inetSSL_ACCEPT()=>%d (%d), '%s'\n", ;
|
|
nResult, nErr, ;
|
|
ERR_error_string( nErr ) )
|
|
|
|
IF nResult == 1
|
|
cLine := hb_inetRecvLine( sockConn )
|
|
? "SERVER: RECV:", hb_ValToExp( cLine )
|
|
hb_inetSendAll( sockConn, ;
|
|
"ECHO[ " + cLine + " ]" + EOL + ;
|
|
hb_TSToStr( hb_DateTime() ) + EOL + ;
|
|
OS() + EOL + ;
|
|
Version() + EOL + ;
|
|
EOL )
|
|
ENDIF
|
|
|
|
hb_inetClose( sockConn )
|
|
sockConn := nil
|
|
ENDIF
|
|
ENDDO
|
|
|
|
s_lReady := .F.
|
|
ENDIF
|
|
|
|
RETURN NIL
|
|
|
|
|
|
STATIC FUNCTION LoadCertificates( ssl_ctx, cCertFile, cKeyFile )
|
|
|
|
/* Server using hb_inetSSL_ACCEPT() needs certificates,
|
|
they can be generated using the following command:
|
|
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
|
-out <cCertFile> -keyout <cKeyFile>
|
|
*/
|
|
IF ! hb_FileExists( cCertFile ) .AND. ! hb_FileExists( cKeyFile )
|
|
? "SERVER: generating certificates..."
|
|
hb_run( "openssl req -x509 -nodes -days 365 -newkey rsa:2048 " + ;
|
|
"-out " + cCertFile + " -keyout " + cKeyFile )
|
|
ENDIF
|
|
|
|
/* set the local certificate from CertFile */
|
|
IF SSL_CTX_use_certificate_file( ssl_ctx, cCertFile, HB_SSL_FILETYPE_PEM ) <= 0
|
|
OutErr( hb_StrFormat( e"SERVER: SSL_CTX_use_certificate_file()=> '%s'\n", ;
|
|
ERR_error_string( ERR_get_error() ) ) )
|
|
QUIT
|
|
ENDIF
|
|
|
|
/* set the private key from KeyFile (may be the same as CertFile) */
|
|
IF SSL_CTX_use_PrivateKey_file( ssl_ctx, cKeyFile, HB_SSL_FILETYPE_PEM ) <= 0
|
|
OutErr( hb_StrFormat( e"SERVER: SSL_CTX_use_PrivateKey_file()=> '%s'\n", ;
|
|
ERR_error_string( ERR_get_error() ) ) )
|
|
QUIT
|
|
ENDIF
|
|
|
|
/* verify private key */
|
|
IF ! SSL_CTX_check_private_key( ssl_ctx ) == 1
|
|
OutErr( e"SERVER: Private key does not match the public certificate\n" )
|
|
QUIT
|
|
ENDIF
|
|
|
|
RETURN NIL
|
|
|
|
|
|
STATIC FUNCTION DispCertInfo( ssl, cWho )
|
|
LOCAL cert
|
|
|
|
IF ! Empty( cert := SSL_get_peer_certificate( ssl ) )
|
|
? cWho + "Server certificates:"
|
|
? cWho + "Subject:", X509_name_oneline( X509_get_subject_name( cert ), 0, 0 )
|
|
? cWho + "Issuer:", X509_name_oneline( X509_get_issuer_name( cert ), 0, 0 )
|
|
ELSE
|
|
? cWho + "No certificates."
|
|
ENDIF
|
|
|
|
RETURN NIL
|