]> Repositorios git - scryer-prolog.git/commitdiff
ADDED: Encrypted client connections in library(sockets) via new option tls/1.
authorMarkus Triska <[email protected]>
Sun, 7 Jun 2020 16:12:29 +0000 (18:12 +0200)
committerMarkus Triska <[email protected]>
Tue, 9 Jun 2020 05:43:29 +0000 (07:43 +0200)
Use tls(true) to negotiate an encrypted network connection via TLS.

Cargo.toml
README.md
src/prolog/clause_types.rs
src/prolog/lib/sockets.pl
src/prolog/machine/streams.rs
src/prolog/machine/system_calls.rs

index 13acfe3447aba1a08505563329a2b5cb0db97f49..4abfc25a1789c5abadb58d54f664bfd4916f5326 100644 (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"
index 022cc5602a8360371539f506700593d0b8629bc8..2a631129f6039e8328dfaed36e78cc4761cf3a70 100644 (file)
--- a/README.md
+++ b/README.md
@@ -409,6 +409,8 @@ The modules that ship with Scryer&nbsp;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),
index fe816cc0112522ba5c43aac0fe4c827fdda682ac..1d90106844b720cdb85b9ef14ebaed72fdf57ce5 100644 (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),
index a006d6a215d30ad5c6a2a4e30532da46548d0efc..108ac9b9464e737f39c10940d5d53916e7db80e9 100644 (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) :-
index 6308017db44bfffbfaab351636c5fd5a692e98f4..1dcbe1459ccc24f0f6936884a4945ed749e8b70e 100644 (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()
             }
index bb470f0e99ad78b30b2fe588af3ab40a8233c774..7d0592bbec8cceacc069c252dfbfc59f78611b94 100644 (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 {