From f88d44f813159c0fe2e646c82517aad7f597bb00 Mon Sep 17 00:00:00 2001 From: kenna-bmcdevitt Date: Wed, 22 Jul 2020 01:00:20 -0500 Subject: [PATCH] added ssl/tls support --- fake_tunnel_connector/.gitignore | 3 + .../fake_tunnel_connector.rb | 35 +++++++----- fake_tunnel_connector/server.rb | 22 +++++++ fake_tunnel_connector/setup_ssl_cert.rb | 8 +++ fake_tunnel_connector/ssl.rb | 57 +++++++++++++++++++ 5 files changed, 112 insertions(+), 13 deletions(-) create mode 100644 fake_tunnel_connector/.gitignore create mode 100755 fake_tunnel_connector/server.rb create mode 100755 fake_tunnel_connector/setup_ssl_cert.rb create mode 100644 fake_tunnel_connector/ssl.rb diff --git a/fake_tunnel_connector/.gitignore b/fake_tunnel_connector/.gitignore new file mode 100644 index 0000000..90b4a6d --- /dev/null +++ b/fake_tunnel_connector/.gitignore @@ -0,0 +1,3 @@ +certificate.pem +private_key.pem +public_key.pem diff --git a/fake_tunnel_connector/fake_tunnel_connector.rb b/fake_tunnel_connector/fake_tunnel_connector.rb index 3bc50d5..e1dcb7e 100644 --- a/fake_tunnel_connector/fake_tunnel_connector.rb +++ b/fake_tunnel_connector/fake_tunnel_connector.rb @@ -3,25 +3,35 @@ require './http.rb' require 'time' class FakeTunnelConnector - attr_accessor :port, :server - def initialize(port) + attr_accessor :port, :server, :ssl_context + def initialize(port, ssl_context = nil) @port = port @server = TCPServer.open(port) + @ssl_context = ssl_context end def listen_and_respond - tcp_socket = server.accept + if ssl_context + tls_server = ssl_server + tcp_socket = tls_server.accept + else + tcp_socket = server.accept + end response = read_socket(tcp_socket) location = response[:start_line][:location] write_response(tcp_socket, location) tcp_socket.close end + def ssl_server + OpenSSL::SSL::SSLServer.new server, ssl_context if ssl_context + end + def read_socket(tcp_socket) start_line = [] headers = [] - puts "Request Incoming:" - puts "-------------------" + puts 'Request Incoming:' + puts '-------------------' # read lines from socket while (line = tcp_socket.gets) && (line.chomp.length > 0) # check for a valid http verb sent @@ -30,11 +40,11 @@ class FakeTunnelConnector headers << header_line unless header_line.nil? end puts start_line - puts "Request Headers:" - puts "-------------------" + puts 'Request Headers:' + puts '-------------------' puts headers puts "\r\n" - {:start_line => start_line, :headers => headers} + { start_line: start_line, headers: headers } end def parse_http_start_request_line(line) @@ -68,14 +78,14 @@ class FakeTunnelConnector tcp_socket.print(ok(route_response_string)) end - def ok(body='Success') + def ok(body = 'Success') body + "\r" end def ok_headers "HTTP/1.1 200 OK\r\n" + - "Date: #{Time.now.utc}\r\n" + - "\r\n" + "Date: #{Time.now.utc}\r\n" + + "\r\n" end def route_request(location) @@ -99,5 +109,4 @@ class FakeTunnelConnector body = '{"token":"797118d801342a0c5c5be3ed5420782becbea2e3bceea9275543dff4ee62dfc4"}' ok(body) end - -end \ No newline at end of file +end diff --git a/fake_tunnel_connector/server.rb b/fake_tunnel_connector/server.rb new file mode 100755 index 0000000..2398f7e --- /dev/null +++ b/fake_tunnel_connector/server.rb @@ -0,0 +1,22 @@ +require 'pry' +require './ssl.rb' +require './http.rb' +require './fake_tunnel_connector.rb' + +port = ARGV[0] +cert_path = './certificate.pem' +key_path = './private_key.pem' + +# lib for easier ssl usage +ssl_helper = SSL.new +# load our self-signed certificate +cert = ssl_helper.load_cert(cert_path) +#binding.pry +key = ssl_helper.load_key(key_path) + +# setup a new ssl context to be used with the tcp server +context = ssl_helper.new_ssl_context(cert, key) + +# setup our server on the port that we pass into the script and listen for https calls. +server = FakeTunnelConnector.new(port, ssl_context=context) +loop { server.listen_and_respond } diff --git a/fake_tunnel_connector/setup_ssl_cert.rb b/fake_tunnel_connector/setup_ssl_cert.rb new file mode 100755 index 0000000..03a582e --- /dev/null +++ b/fake_tunnel_connector/setup_ssl_cert.rb @@ -0,0 +1,8 @@ +require './ssl.rb' + +ssl_helper = SSL.new +cert, name, key = ssl_helper.generate_cert +signed_key = ssl_helper.self_sign_key(cert, name, key) + +puts "you should now have a certificate.pem in the current working directory" +puts "you should now have a public_key.pem and a private_key.pem in the current working directory." diff --git a/fake_tunnel_connector/ssl.rb b/fake_tunnel_connector/ssl.rb new file mode 100644 index 0000000..198ebd5 --- /dev/null +++ b/fake_tunnel_connector/ssl.rb @@ -0,0 +1,57 @@ +require 'openssl' + +class SSL + def initialize; end + + def generate_cert + key = generate_keypair(2048) + name = OpenSSL::X509::Name.parse('/CN=nobody/DC=example') + + cert = OpenSSL::X509::Certificate.new + cert.version = 2 + cert.serial = 0 + cert.not_before = Time.now + cert.not_after = Time.now + 3600 + cert.public_key = key.public_key + cert.subject = name + [cert, name, key] + end + + def generate_keypair(size) + key = generate_key(size) + open 'private_key.pem', 'w' do |io| io.write key.to_pem end + open 'public_key.pem', 'w' do |io| io.write key.public_key.to_pem end + key + end + + def generate_key(size) + OpenSSL::PKey::RSA.new size + end + + def load_key(path, passphrase = nil) + if passphrase + OpenSSL::PKey::RSA.new(File.read(path), passphrase) + else + OpenSSL::PKey::RSA.new(File.read(path)) + end + end + + # sign cert generated from generate_cert method. + # cert, name, key = generate_cert + def self_sign_key(cert, name, key) + cert.issuer = name + cert.sign key, OpenSSL::Digest.new('SHA1') + open 'certificate.pem', 'w' do |io| io.write cert.to_pem end + end + + def new_ssl_context(cert, key) + context = OpenSSL::SSL::SSLContext.new + context.cert = cert + context.key = key + context + end + + def load_cert(path) + OpenSSL::X509::Certificate.new File.read path + end +end