ADDED: Encrypted client connections in library(sockets) via new option tls/1.

Use tls(true) to negotiate an encrypted network connection via TLS.
This commit is contained in:
Markus Triska
2020-06-07 18:12:29 +02:00
parent d5e76da475
commit 7b30daf88d
6 changed files with 70 additions and 7 deletions

View File

@@ -42,3 +42,4 @@ ripemd160 = "0.8.0"
sha3 = "0.8.2"
blake2 = "0.8.1"
openssl = { version = "0.10.29", features = ["vendored"] }
native-tls = "0.2.4"

View File

@@ -409,6 +409,8 @@ The modules that ship with Scryer Prolog are also called
Probabilistic predicates and random number generators.
* [`sockets`](src/prolog/lib/sockets.pl)
Predicates for opening and accepting TCP connections as streams.
TLS negotiation is performed via the option `tls(true)` in
`socket_client_open/3`, yielding secure encrypted connections.
* [`crypto`](src/prolog/lib/crypto.pl)
Cryptographically secure random numbers and hashes, HMAC-based
key derivation (HKDF), password-based key derivation (PBKDF2),

View File

@@ -635,7 +635,7 @@ impl SystemClauseType {
("$set_seed", 1) => Some(SystemClauseType::SetSeed),
("$skip_max_list", 4) => Some(SystemClauseType::SkipMaxList),
("$sleep", 1) => Some(SystemClauseType::Sleep),
("$socket_client_open", 7) => Some(SystemClauseType::SocketClientOpen),
("$socket_client_open", 8) => Some(SystemClauseType::SocketClientOpen),
("$socket_server_open", 3) => Some(SystemClauseType::SocketServerOpen),
("$socket_server_accept", 7) => Some(SystemClauseType::SocketServerAccept),
("$socket_server_close", 1) => Some(SystemClauseType::SocketServerClose),

View File

@@ -6,7 +6,16 @@
current_hostname/1]).
:- use_module(library(error)).
:- use_module(library(lists)).
parse_socket_options_(tls(TLS), tls-TLS) :-
must_be(boolean, TLS), !.
parse_socket_options_(Option, OptionPair) :-
builtins:parse_stream_options_(Option, OptionPair).
parse_socket_options(Options, OptionValues, Stub) :-
DefaultOptions = [alias-[], eof_action-eof_code, reposition-false, tls-false, type-text],
builtins:parse_options_list(Options, parse_socket_options_, DefaultOptions, OptionValues, Stub).
socket_client_open(Addr, Stream, Options) :-
( var(Addr) ->
@@ -23,10 +32,10 @@ socket_client_open(Addr, Stream, Options) :-
;
throw(error(type_error(socket_address, Addr), socket_client_open/3))
),
builtins:parse_stream_options(Options,
[Alias, EOFAction, Reposition, Type],
socket_client_open/3),
'$socket_client_open'(Address, Port, Stream, Alias, EOFAction, Reposition, Type).
parse_socket_options(Options,
[Alias, EOFAction, Reposition, TLS, Type],
socket_client_open/3),
'$socket_client_open'(Address, Port, Stream, Alias, EOFAction, Reposition, Type, TLS).
socket_server_open(Addr, ServerSocket) :-

View File

@@ -17,6 +17,8 @@ use std::net::{Shutdown, TcpStream};
use std::ops::DerefMut;
use std::rc::Rc;
use native_tls::TlsStream;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum StreamType {
Binary,
@@ -101,6 +103,7 @@ pub enum StreamInstance {
ReadlineStream(ReadlineStream),
Stdout,
TcpStream(ClauseName, TcpStream),
TlsStream(ClauseName, TlsStream<TcpStream>)
}
impl Drop for StreamInstance {
@@ -109,6 +112,9 @@ impl Drop for StreamInstance {
StreamInstance::TcpStream(_, ref mut tcp_stream) => {
discard_result!(tcp_stream.shutdown(Shutdown::Both));
}
StreamInstance::TlsStream(_, ref mut tls_stream) => {
discard_result!(tls_stream.shutdown());
}
_ => {
}
}
@@ -131,6 +137,8 @@ impl fmt::Debug for StreamInstance {
&StreamInstance::Stdout => write!(fmt, "Stdout"),
&StreamInstance::TcpStream(_, ref tcp_stream) =>
write!(fmt, "TcpStream({:?})", tcp_stream),
&StreamInstance::TlsStream(_, ref tls_stream) =>
write!(fmt, "TlsStream({:?})", tls_stream),
}
}
}
@@ -410,7 +418,8 @@ impl Stream {
StreamInstance::InputFile(..) => {
"read"
}
StreamInstance::TcpStream(..) => {
StreamInstance::TcpStream(..) |
StreamInstance::TlsStream(..) => {
"read_append"
}
StreamInstance::OutputFile(_, _, true) => {
@@ -449,6 +458,12 @@ impl Stream {
Stream::from_inst(StreamInstance::TcpStream(address, tcp_stream))
}
#[inline]
pub(crate)
fn from_tls_stream(address: ClauseName, tls_stream: TlsStream<TcpStream>) -> Self {
Stream::from_inst(StreamInstance::TlsStream(address, tls_stream))
}
#[inline]
pub(crate)
fn from_file_as_output(name: ClauseName, file: File, in_append_mode: bool) -> Self {
@@ -510,6 +525,7 @@ impl Stream {
match self.stream_inst.0.borrow().1 {
// StreamInstance::Stdin |
StreamInstance::TcpStream(..) |
StreamInstance::TlsStream(..) |
StreamInstance::Bytes(_) |
StreamInstance::ReadlineStream(_) |
StreamInstance::DynReadSource(_) |
@@ -528,6 +544,7 @@ impl Stream {
match self.stream_inst.0.borrow().1 {
StreamInstance::Stdout
| StreamInstance::TcpStream(..)
| StreamInstance::TlsStream(..)
| StreamInstance::Bytes(_)
| StreamInstance::OutputFile(..) => {
true
@@ -1036,6 +1053,9 @@ impl Read for Stream {
StreamInstance::TcpStream(_, ref mut tcp_stream) => {
tcp_stream.read(buf)
}
StreamInstance::TlsStream(_, ref mut tls_stream) => {
tls_stream.read(buf)
}
StreamInstance::ReadlineStream(ref mut rl_stream) => {
rl_stream.read(buf)
}
@@ -1069,6 +1089,9 @@ impl Write for Stream {
StreamInstance::TcpStream(_, ref mut tcp_stream) => {
tcp_stream.write(buf)
}
StreamInstance::TlsStream(_, ref mut tls_stream) => {
tls_stream.write(buf)
}
StreamInstance::Bytes(ref mut cursor) => {
cursor.write(buf)
}
@@ -1093,6 +1116,9 @@ impl Write for Stream {
StreamInstance::TcpStream(_, ref mut tcp_stream) => {
tcp_stream.flush()
}
StreamInstance::TlsStream(_, ref mut tls_stream) => {
tls_stream.flush()
}
StreamInstance::Bytes(ref mut cursor) => {
cursor.flush()
}

View File

@@ -49,6 +49,8 @@ use openssl::ec::{EcGroup, EcPoint};
use openssl::bn::{BigNum, BigNumContext};
use openssl::nid::Nid;
use native_tls::TlsConnector;
pub fn get_key() -> KeyEvent {
let key;
enable_raw_mode().expect("failed to enable raw mode");
@@ -4517,7 +4519,30 @@ impl MachineState {
Ok(tcp_stream) => {
let socket_addr = clause_name!(socket_addr, indices.atom_tbl.clone());
let mut stream = Stream::from_tcp_stream(socket_addr, tcp_stream);
let mut stream =
{ let tls = match self.store(self.deref(self[temp_v!(8)])) {
Addr::Con(h) if self.heap.atom_at(h) => {
if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
atom.as_str()
} else {
unreachable!()
}
}
_ => {
unreachable!()
}
};
match tls {
"false" => { Stream::from_tcp_stream(socket_addr, tcp_stream) }
"true" => { let connector = TlsConnector::new().unwrap();
let stream = connector.connect(socket_atom.as_str(), tcp_stream).unwrap();
Stream::from_tls_stream(socket_addr, stream)
}
_ => { unreachable!() }
}
};
stream.options = options;
if let Some(ref alias) = &stream.options.alias {