diff options
Diffstat (limited to 'v_windows/v/old/vlib/net/openssl')
| -rw-r--r-- | v_windows/v/old/vlib/net/openssl/c.v | 120 | ||||
| -rw-r--r-- | v_windows/v/old/vlib/net/openssl/openssl.v | 32 | ||||
| -rw-r--r-- | v_windows/v/old/vlib/net/openssl/ssl_connection.v | 268 | 
3 files changed, 420 insertions, 0 deletions
| diff --git a/v_windows/v/old/vlib/net/openssl/c.v b/v_windows/v/old/vlib/net/openssl/c.v new file mode 100644 index 0000000..dedba2a --- /dev/null +++ b/v_windows/v/old/vlib/net/openssl/c.v @@ -0,0 +1,120 @@ +module openssl + +// On Linux, prefer a localy built openssl, because it is +// much more likely for it to be newer, than the system +// openssl from libssl-dev. If there is no local openssl, +// the next flag is harmless, since it will still use the +// (older) system openssl. +#flag linux -I/usr/local/include/openssl -L/usr/local/lib +#flag windows -l libssl -l libcrypto +#flag -lssl -lcrypto +#flag linux -ldl -lpthread +// MacPorts +#flag darwin -I/opt/local/include +#flag darwin -L/opt/local/lib +// Brew +#flag darwin -I/usr/local/opt/openssl/include +#flag darwin -L/usr/local/opt/openssl/lib +// Brew arm64 +#flag darwin -I /opt/homebrew/opt/openssl/include +#flag darwin -L /opt/homebrew/opt/openssl/lib +// +#include <openssl/rand.h> # Please install OpenSSL development headers +#include <openssl/ssl.h> +#include <openssl/err.h> + +pub struct C.SSL { +} + +pub struct SSL_CTX { +} + +pub struct SSL { +} + +pub struct SSL_METHOD { +} + +pub struct OPENSSL_INIT_SETTINGS { +} + +fn C.BIO_new_ssl_connect(ctx &C.SSL_CTX) &C.BIO + +fn C.BIO_set_conn_hostname(b &C.BIO, name &char) int + +// there are actually 2 macros for BIO_get_ssl +// fn C.BIO_get_ssl(bp &C.BIO, ssl charptr, c int) +// fn C.BIO_get_ssl(bp &C.BIO, sslp charptr) +fn C.BIO_get_ssl(bp &C.BIO, vargs ...voidptr) + +fn C.BIO_do_connect(b &C.BIO) int + +fn C.BIO_do_handshake(b &C.BIO) int + +fn C.BIO_puts(b &C.BIO, buf &char) + +fn C.BIO_read(b &C.BIO, buf voidptr, len int) int + +fn C.BIO_free_all(a &C.BIO) + +fn C.SSL_CTX_new(method &C.SSL_METHOD) &C.SSL_CTX + +fn C.SSL_CTX_set_options(ctx &C.SSL_CTX, options int) + +fn C.SSL_CTX_set_verify_depth(s &C.SSL_CTX, depth int) + +fn C.SSL_CTX_load_verify_locations(ctx &C.SSL_CTX, ca_file &char, ca_path &char) int + +fn C.SSL_CTX_free(ctx &C.SSL_CTX) + +fn C.SSL_new(&C.SSL_CTX) &C.SSL + +fn C.SSL_set_fd(ssl &C.SSL, fd int) int + +fn C.SSL_connect(&C.SSL) int + +fn C.SSL_set_cipher_list(ctx &SSL, str &char) int + +fn C.SSL_get_peer_certificate(ssl &SSL) &C.X509 + +fn C.ERR_clear_error() + +fn C.SSL_get_error(ssl &C.SSL, ret int) int + +fn C.SSL_get_verify_result(ssl &SSL) int + +fn C.SSL_set_tlsext_host_name(s &SSL, name &char) int + +fn C.SSL_shutdown(&C.SSL) int + +fn C.SSL_free(&C.SSL) + +fn C.SSL_write(ssl &C.SSL, buf voidptr, buflen int) int + +fn C.SSL_read(ssl &C.SSL, buf voidptr, buflen int) int + +fn C.SSL_load_error_strings() + +fn C.SSL_library_init() int + +fn C.SSLv23_client_method() &C.SSL_METHOD + +fn C.TLS_method() voidptr + +fn C.TLSv1_2_method() voidptr + +fn C.OPENSSL_init_ssl(opts u64, settings &OPENSSL_INIT_SETTINGS) int + +fn init() { +	$if ssl_pre_1_1_version ? { +		// OPENSSL_VERSION_NUMBER < 0x10100000L +		C.SSL_load_error_strings() +		C.SSL_library_init() +	} $else { +		C.OPENSSL_init_ssl(C.OPENSSL_INIT_LOAD_SSL_STRINGS, 0) +	} +} + +pub const ( +	is_used = 1 +) diff --git a/v_windows/v/old/vlib/net/openssl/openssl.v b/v_windows/v/old/vlib/net/openssl/openssl.v new file mode 100644 index 0000000..ffcabf5 --- /dev/null +++ b/v_windows/v/old/vlib/net/openssl/openssl.v @@ -0,0 +1,32 @@ +module openssl + +// ssl_error returns non error ssl code or error if unrecoverable and we should panic +pub fn ssl_error(ret int, ssl voidptr) ?SSLError { +	res := C.SSL_get_error(ssl, ret) +	match SSLError(res) { +		.ssl_error_syscall { +			return error_with_code('unrecoverable syscall ($res)', res) +		} +		.ssl_error_ssl { +			return error_with_code('unrecoverable ssl protocol error ($res)', res) +		} +		else { +			return SSLError(res) +		} +	} +} + +pub enum SSLError { +	ssl_error_none = 0 // SSL_ERROR_NONE +	ssl_error_ssl = 1 // SSL_ERROR_SSL +	ssl_error_want_read = 2 // SSL_ERROR_WANT_READ +	ssl_error_want_write = 3 // SSL_ERROR_WANT_WRITE +	ssl_error_want_x509_lookup = 4 // SSL_ERROR_WANT_X509_LOOKUP +	ssl_error_syscall = 5 // SSL_ERROR_SYSCALL +	ssl_error_zero_return = 6 // SSL_ERROR_ZERO_RETURN +	ssl_error_want_connect = 7 // SSL_ERROR_WANT_CONNECT +	ssl_error_want_accept = 8 // SSL_ERROR_WANT_ACCEPT +	ssl_error_want_async = 9 // SSL_ERROR_WANT_ASYNC +	ssl_error_want_async_job = 10 // SSL_ERROR_WANT_ASYNC_JOB +	ssl_error_want_early = 11 // SSL_ERROR_WANT_EARLY +} diff --git a/v_windows/v/old/vlib/net/openssl/ssl_connection.v b/v_windows/v/old/vlib/net/openssl/ssl_connection.v new file mode 100644 index 0000000..58f47f6 --- /dev/null +++ b/v_windows/v/old/vlib/net/openssl/ssl_connection.v @@ -0,0 +1,268 @@ +module openssl + +import net +import time + +// SSLConn is the current connection +pub struct SSLConn { +mut: +	sslctx   &C.SSL_CTX +	ssl      &C.SSL +	handle   int +	duration time.Duration +} + +// new_ssl_conn instance an new SSLCon struct +pub fn new_ssl_conn() &SSLConn { +	return &SSLConn{ +		sslctx: 0 +		ssl: 0 +		handle: 0 +	} +} + +// Select operation +enum Select { +	read +	write +	except +} + +// shutdown closes the ssl connection and do clean up +pub fn (mut s SSLConn) shutdown() ? { +	if s.ssl != 0 { +		mut res := 0 +		for { +			res = C.SSL_shutdown(voidptr(s.ssl)) +			if res < 0 { +				err_res := ssl_error(res, s.ssl) or { +					break // We break to free rest of resources +				} +				if err_res == .ssl_error_want_read { +					for { +						ready := @select(s.handle, .read, s.duration) ? +						if ready { +							break +						} +					} +					continue +				} else if err_res == .ssl_error_want_write { +					for { +						ready := @select(s.handle, .write, s.duration) ? +						if ready { +							break +						} +					} +					continue +				} else { +					unsafe { C.SSL_free(voidptr(s.ssl)) } +					if s.sslctx != 0 { +						C.SSL_CTX_free(s.sslctx) +					} +					return error('unexepedted ssl error $err_res') +				} +				if s.ssl != 0 { +					unsafe { C.SSL_free(voidptr(s.ssl)) } +				} +				if s.sslctx != 0 { +					C.SSL_CTX_free(s.sslctx) +				} +				return error('Could not connect using SSL. ($err_res),err') +			} else if res == 0 { +				continue +			} else if res == 1 { +				break +			} +		} +		C.SSL_free(voidptr(s.ssl)) +	} +	if s.sslctx != 0 { +		C.SSL_CTX_free(s.sslctx) +	} +} + +// connect to server using open ssl +pub fn (mut s SSLConn) connect(mut tcp_conn net.TcpConn, hostname string) ? { +	s.handle = tcp_conn.sock.handle +	s.duration = tcp_conn.read_timeout() + +	s.sslctx = unsafe { C.SSL_CTX_new(C.SSLv23_client_method()) } +	if s.sslctx == 0 { +		return error("Couldn't get ssl context") +	} + +	// TODO: Fix option to enable/disable checks for valid +	//		 certificates to allow both secure and self signed +	//		 for now the checks are not done at all to comply +	// 		 to current autobahn tests + +	// C.SSL_CTX_set_verify_depth(s.sslctx, 4) +	// flags := C.SSL_OP_NO_SSLv2 | C.SSL_OP_NO_SSLv3 | C.SSL_OP_NO_COMPRESSION +	// C.SSL_CTX_set_options(s.sslctx, flags) +	// mut res := C.SSL_CTX_load_verify_locations(s.sslctx, 'random-org-chain.pem', 0) + +	s.ssl = unsafe { &C.SSL(C.SSL_new(s.sslctx)) } +	if s.ssl == 0 { +		return error("Couldn't create OpenSSL instance.") +	} + +	// preferred_ciphers := 'HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4' +	// mut res := C.SSL_set_cipher_list(s.ssl, preferred_ciphers.str) +	// if res != 1 { +	// 	println('http: openssl: cipher failed') +	// } + +	mut res := C.SSL_set_tlsext_host_name(voidptr(s.ssl), voidptr(hostname.str)) +	if res != 1 { +		return error('cannot set host name') +	} + +	if C.SSL_set_fd(voidptr(s.ssl), tcp_conn.sock.handle) != 1 { +		return error("Couldn't assign ssl to socket.") +	} +	for { +		res = C.SSL_connect(voidptr(s.ssl)) +		if res != 1 { +			err_res := ssl_error(res, s.ssl) ? +			if err_res == .ssl_error_want_read { +				for { +					ready := @select(s.handle, .read, s.duration) ? +					if ready { +						break +					} +				} +				continue +			} else if err_res == .ssl_error_want_write { +				for { +					ready := @select(s.handle, .write, s.duration) ? +					if ready { +						break +					} +				} +				continue +			} +			return error('Could not connect using SSL. ($err_res),err') +		} +		break +	} +} + +pub fn (mut s SSLConn) socket_read_into_ptr(buf_ptr &byte, len int) ?int { +	mut res := 0 +	for { +		res = C.SSL_read(voidptr(s.ssl), buf_ptr, len) +		if res < 0 { +			err_res := ssl_error(res, s.ssl) ? +			if err_res == .ssl_error_want_read { +				for { +					ready := @select(s.handle, .read, s.duration) ? +					if ready { +						break +					} +				} +				continue +			} else if err_res == .ssl_error_want_write { +				for { +					ready := @select(s.handle, .write, s.duration) ? +					if ready { +						break +					} +				} +				continue +			} else if err_res == .ssl_error_zero_return { +				return 0 +			} +			return error('Could not read using SSL. ($err_res)') +		} +		break +	} +	return res +} + +pub fn (mut s SSLConn) read_into(mut buffer []byte) ?int { +	res := s.socket_read_into_ptr(&byte(buffer.data), buffer.len) ? +	return res +} + +// write number of bytes to SSL connection +pub fn (mut s SSLConn) write(bytes []byte) ?int { +	unsafe { +		mut ptr_base := &byte(bytes.data) +		mut total_sent := 0 +		for total_sent < bytes.len { +			ptr := ptr_base + total_sent +			remaining := bytes.len - total_sent +			mut sent := C.SSL_write(voidptr(s.ssl), ptr, remaining) +			if sent <= 0 { +				err_res := ssl_error(sent, s.ssl) ? +				if err_res == .ssl_error_want_read { +					for { +						ready := @select(s.handle, .read, s.duration) ? +						if ready { +							break +						} +					} +				} else if err_res == .ssl_error_want_write { +					for { +						ready := @select(s.handle, .write, s.duration) ? +						if ready { +							break +						} +					} +					continue +				} else if err_res == .ssl_error_zero_return { +					return error('ssl write on closed connection') // Todo error_with_code close +				} +				return error_with_code('Could not write SSL. ($err_res),err', int(err_res)) +			} +			total_sent += sent +		} +		return total_sent +	} +} + +/* +This is basically a copy of Emily socket implementation of select. +	This have to be consolidated into common net lib features +	when merging this to V +*/ +// [typedef] +// pub struct C.fd_set { +// } + +// Select waits for an io operation (specified by parameter `test`) to be available +fn @select(handle int, test Select, timeout time.Duration) ?bool { +	set := C.fd_set{} + +	C.FD_ZERO(&set) +	C.FD_SET(handle, &set) + +	seconds := timeout.milliseconds() / 1000 +	microseconds := timeout - (seconds * time.second) +	mut tt := C.timeval{ +		tv_sec: u64(seconds) +		tv_usec: u64(microseconds) +	} + +	mut timeval_timeout := &tt + +	// infinite timeout is signaled by passing null as the timeout to +	// select +	if timeout == net.infinite_timeout { +		timeval_timeout = &C.timeval(0) +	} + +	match test { +		.read { +			net.socket_error(C.@select(handle + 1, &set, C.NULL, C.NULL, timeval_timeout)) ? +		} +		.write { +			net.socket_error(C.@select(handle + 1, C.NULL, &set, C.NULL, timeval_timeout)) ? +		} +		.except { +			net.socket_error(C.@select(handle + 1, C.NULL, C.NULL, &set, timeval_timeout)) ? +		} +	} + +	return C.FD_ISSET(handle, &set) +} | 
