ruby-tls 1.0.2 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/EM-LICENSE +60 -60
- data/README.md +71 -71
- data/Rakefile +19 -19
- data/ext/Rakefile +18 -18
- data/ext/tls/page.cpp +102 -102
- data/ext/tls/page.h +61 -61
- data/ext/tls/ssl.cpp +594 -587
- data/ext/tls/ssl.h +130 -129
- data/lib/ruby-tls.rb +7 -7
- data/lib/ruby-tls/connection.rb +124 -121
- data/lib/ruby-tls/ext.rb +39 -38
- data/lib/ruby-tls/version.rb +3 -3
- data/ruby-tls.gemspec +32 -32
- data/spec/client.crt +31 -31
- data/spec/client.key +51 -51
- data/spec/comms_spec.rb +156 -147
- data/spec/verify_spec.rb +120 -118
- metadata +34 -34
data/ext/tls/ssl.h
CHANGED
@@ -1,129 +1,130 @@
|
|
1
|
-
/*****************************************************************************
|
2
|
-
|
3
|
-
$Id$
|
4
|
-
|
5
|
-
File: ssl.h
|
6
|
-
Date: 30Apr06
|
7
|
-
|
8
|
-
Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
|
9
|
-
Gmail: blackhedd
|
10
|
-
|
11
|
-
This program is free software; you can redistribute it and/or modify
|
12
|
-
it under the terms of either: 1) the GNU General Public License
|
13
|
-
as published by the Free Software Foundation; either version 2 of the
|
14
|
-
License, or (at your option) any later version; or 2) Ruby's License.
|
15
|
-
|
16
|
-
See the file COPYING for complete licensing information.
|
17
|
-
|
18
|
-
*****************************************************************************/
|
19
|
-
|
20
|
-
|
21
|
-
#ifndef __SslBox__H_
|
22
|
-
#define __SslBox__H_
|
23
|
-
|
24
|
-
#include <iostream>
|
25
|
-
#include <string>
|
26
|
-
|
27
|
-
#include <openssl/ssl.h>
|
28
|
-
#include <openssl/err.h>
|
29
|
-
|
30
|
-
#include <assert.h>
|
31
|
-
|
32
|
-
#include "page.h"
|
33
|
-
|
34
|
-
using namespace std;
|
35
|
-
|
36
|
-
|
37
|
-
/******************
|
38
|
-
class SslContext_t
|
39
|
-
******************/
|
40
|
-
|
41
|
-
class SslContext_t
|
42
|
-
{
|
43
|
-
public:
|
44
|
-
SslContext_t (bool is_server, const string &privkeyfile, const string &certchainfile);
|
45
|
-
virtual ~SslContext_t();
|
46
|
-
|
47
|
-
private:
|
48
|
-
bool bIsServer;
|
49
|
-
SSL_CTX *pCtx;
|
50
|
-
|
51
|
-
EVP_PKEY *PrivateKey;
|
52
|
-
X509 *Certificate;
|
53
|
-
|
54
|
-
friend class SslBox_t;
|
55
|
-
};
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
typedef struct tls_state_s tls_state_t;
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
/**************
|
65
|
-
class SslBox_t
|
66
|
-
**************/
|
67
|
-
|
68
|
-
class SslBox_t
|
69
|
-
{
|
70
|
-
public:
|
71
|
-
SslBox_t (tls_state_t *tls_state, bool is_server, const string &privkeyfile, const string &certchainfile, bool verify_peer);
|
72
|
-
virtual ~SslBox_t();
|
73
|
-
|
74
|
-
int PutPlaintext (const char*, int);
|
75
|
-
int GetPlaintext (char*, int);
|
76
|
-
|
77
|
-
bool PutCiphertext (const char*, int);
|
78
|
-
bool CanGetCiphertext();
|
79
|
-
int GetCiphertext (char*, int);
|
80
|
-
bool IsHandshakeCompleted() { return bHandshakeCompleted; }
|
81
|
-
|
82
|
-
X509 *GetPeerCert();
|
83
|
-
|
84
|
-
void Shutdown();
|
85
|
-
|
86
|
-
protected:
|
87
|
-
SslContext_t *Context;
|
88
|
-
|
89
|
-
bool bIsServer;
|
90
|
-
bool bHandshakeCompleted;
|
91
|
-
bool bVerifyPeer;
|
92
|
-
SSL *pSSL;
|
93
|
-
BIO *pbioRead;
|
94
|
-
BIO *pbioWrite;
|
95
|
-
|
96
|
-
PageList OutboundQ;
|
97
|
-
};
|
98
|
-
|
99
|
-
|
100
|
-
typedef void (*ssl_close_cb)(const tls_state_t*);
|
101
|
-
typedef int (*ssl_verify_cb)(const tls_state_t*, const char *cert);
|
102
|
-
typedef void (*ssl_dispatch_cb)(const tls_state_t*, const char *buffer, int size);
|
103
|
-
typedef void (*ssl_transmit_cb)(const tls_state_t*, const char *buffer, int size);
|
104
|
-
typedef void (*ssl_handshake_cb)(const tls_state_t*);
|
105
|
-
|
106
|
-
struct tls_state_s {
|
107
|
-
int handshake_signaled;
|
108
|
-
|
109
|
-
ssl_close_cb close_cb;
|
110
|
-
ssl_verify_cb verify_cb;
|
111
|
-
ssl_dispatch_cb dispatch_cb;
|
112
|
-
ssl_transmit_cb transmit_cb;
|
113
|
-
ssl_handshake_cb handshake_cb;
|
114
|
-
|
115
|
-
SslBox_t* SslBox;
|
116
|
-
};
|
117
|
-
|
118
|
-
|
119
|
-
extern "C" int ssl_verify_wrapper(int preverify_ok, X509_STORE_CTX *ctx);
|
120
|
-
|
121
|
-
extern "C" void start_tls(tls_state_t *tls_state, bool bIsServer, const char *PrivateKeyFilename, const char *CertChainFilename, bool bSslVerifyPeer);
|
122
|
-
extern "C" void
|
123
|
-
extern "C" void
|
124
|
-
extern "C"
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
1
|
+
/*****************************************************************************
|
2
|
+
|
3
|
+
$Id$
|
4
|
+
|
5
|
+
File: ssl.h
|
6
|
+
Date: 30Apr06
|
7
|
+
|
8
|
+
Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
|
9
|
+
Gmail: blackhedd
|
10
|
+
|
11
|
+
This program is free software; you can redistribute it and/or modify
|
12
|
+
it under the terms of either: 1) the GNU General Public License
|
13
|
+
as published by the Free Software Foundation; either version 2 of the
|
14
|
+
License, or (at your option) any later version; or 2) Ruby's License.
|
15
|
+
|
16
|
+
See the file COPYING for complete licensing information.
|
17
|
+
|
18
|
+
*****************************************************************************/
|
19
|
+
|
20
|
+
|
21
|
+
#ifndef __SslBox__H_
|
22
|
+
#define __SslBox__H_
|
23
|
+
|
24
|
+
#include <iostream>
|
25
|
+
#include <string>
|
26
|
+
|
27
|
+
#include <openssl/ssl.h>
|
28
|
+
#include <openssl/err.h>
|
29
|
+
|
30
|
+
#include <assert.h>
|
31
|
+
|
32
|
+
#include "page.h"
|
33
|
+
|
34
|
+
using namespace std;
|
35
|
+
|
36
|
+
|
37
|
+
/******************
|
38
|
+
class SslContext_t
|
39
|
+
******************/
|
40
|
+
|
41
|
+
class SslContext_t
|
42
|
+
{
|
43
|
+
public:
|
44
|
+
SslContext_t (bool is_server, const string &privkeyfile, const string &certchainfile);
|
45
|
+
virtual ~SslContext_t();
|
46
|
+
|
47
|
+
private:
|
48
|
+
bool bIsServer;
|
49
|
+
SSL_CTX *pCtx;
|
50
|
+
|
51
|
+
EVP_PKEY *PrivateKey;
|
52
|
+
X509 *Certificate;
|
53
|
+
|
54
|
+
friend class SslBox_t;
|
55
|
+
};
|
56
|
+
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
typedef struct tls_state_s tls_state_t;
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
/**************
|
65
|
+
class SslBox_t
|
66
|
+
**************/
|
67
|
+
|
68
|
+
class SslBox_t
|
69
|
+
{
|
70
|
+
public:
|
71
|
+
SslBox_t (tls_state_t *tls_state, bool is_server, const string &privkeyfile, const string &certchainfile, bool verify_peer);
|
72
|
+
virtual ~SslBox_t();
|
73
|
+
|
74
|
+
int PutPlaintext (const char*, int);
|
75
|
+
int GetPlaintext (char*, int);
|
76
|
+
|
77
|
+
bool PutCiphertext (const char*, int);
|
78
|
+
bool CanGetCiphertext();
|
79
|
+
int GetCiphertext (char*, int);
|
80
|
+
bool IsHandshakeCompleted() { return bHandshakeCompleted; }
|
81
|
+
|
82
|
+
X509 *GetPeerCert();
|
83
|
+
|
84
|
+
void Shutdown();
|
85
|
+
|
86
|
+
protected:
|
87
|
+
SslContext_t *Context;
|
88
|
+
|
89
|
+
bool bIsServer;
|
90
|
+
bool bHandshakeCompleted;
|
91
|
+
bool bVerifyPeer;
|
92
|
+
SSL *pSSL;
|
93
|
+
BIO *pbioRead;
|
94
|
+
BIO *pbioWrite;
|
95
|
+
|
96
|
+
PageList OutboundQ;
|
97
|
+
};
|
98
|
+
|
99
|
+
|
100
|
+
typedef void (*ssl_close_cb)(const tls_state_t*);
|
101
|
+
typedef int (*ssl_verify_cb)(const tls_state_t*, const char *cert);
|
102
|
+
typedef void (*ssl_dispatch_cb)(const tls_state_t*, const char *buffer, int size);
|
103
|
+
typedef void (*ssl_transmit_cb)(const tls_state_t*, const char *buffer, int size);
|
104
|
+
typedef void (*ssl_handshake_cb)(const tls_state_t*);
|
105
|
+
|
106
|
+
struct tls_state_s {
|
107
|
+
int handshake_signaled;
|
108
|
+
|
109
|
+
ssl_close_cb close_cb;
|
110
|
+
ssl_verify_cb verify_cb;
|
111
|
+
ssl_dispatch_cb dispatch_cb;
|
112
|
+
ssl_transmit_cb transmit_cb;
|
113
|
+
ssl_handshake_cb handshake_cb;
|
114
|
+
|
115
|
+
SslBox_t* SslBox;
|
116
|
+
};
|
117
|
+
|
118
|
+
|
119
|
+
extern "C" int ssl_verify_wrapper(int preverify_ok, X509_STORE_CTX *ctx);
|
120
|
+
|
121
|
+
extern "C" void start_tls(tls_state_t *tls_state, bool bIsServer, const char *PrivateKeyFilename, const char *CertChainFilename, bool bSslVerifyPeer);
|
122
|
+
extern "C" void cleanup(tls_state_t *tls_state);
|
123
|
+
extern "C" void decrypt_data(tls_state_t *tls_state, const char *buffer, int size);
|
124
|
+
extern "C" void encrypt_data(tls_state_t *tls_state, const char *data, int length);
|
125
|
+
extern "C" X509 *get_peer_cert(tls_state_t *tls_state);
|
126
|
+
|
127
|
+
extern "C" void init_rubytls();
|
128
|
+
|
129
|
+
|
130
|
+
#endif // __SslBox__H_
|
data/lib/ruby-tls.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
require "ffi" # Bindings to C libraries
|
2
|
-
|
3
|
-
require "ruby-tls/ext" # Loads the ext using FFI
|
4
|
-
require "ruby-tls/connection" # The ruby abstraction
|
5
|
-
|
6
|
-
module RubyTls
|
7
|
-
end
|
1
|
+
require "ffi" # Bindings to C libraries
|
2
|
+
|
3
|
+
require "ruby-tls/ext" # Loads the ext using FFI
|
4
|
+
require "ruby-tls/connection" # The ruby abstraction
|
5
|
+
|
6
|
+
module RubyTls
|
7
|
+
end
|
data/lib/ruby-tls/connection.rb
CHANGED
@@ -1,121 +1,124 @@
|
|
1
|
-
|
2
|
-
module RubyTls
|
3
|
-
class Connection
|
4
|
-
CALLBACKS = [:close_cb, :verify_cb, :dispatch_cb, :transmit_cb, :handshake_cb]
|
5
|
-
|
6
|
-
|
7
|
-
#
|
8
|
-
#
|
9
|
-
|
10
|
-
|
11
|
-
@
|
12
|
-
@
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
::RubyTls.encrypt_data(@state, data, data.length)
|
78
|
-
end
|
79
|
-
|
80
|
-
def decrypt(data)
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
end
|
1
|
+
|
2
|
+
module RubyTls
|
3
|
+
class Connection
|
4
|
+
CALLBACKS = [:close_cb, :verify_cb, :dispatch_cb, :transmit_cb, :handshake_cb].freeze
|
5
|
+
Callbacks = Struct.new(*CALLBACKS)
|
6
|
+
|
7
|
+
#
|
8
|
+
# Initializes the State instance.
|
9
|
+
#
|
10
|
+
def initialize(callback_obj = nil)
|
11
|
+
@state = ::RubyTls::State.new
|
12
|
+
@callbacks = Callbacks.new # so GC doesn't clean them up on java
|
13
|
+
@started = false
|
14
|
+
|
15
|
+
# Attach callbacks if there is an object passed in to handle the callbacks
|
16
|
+
if not callback_obj.nil?
|
17
|
+
CALLBACKS.each do |callback|
|
18
|
+
self.__send__(callback, &callback_obj.method(callback)) if callback_obj.respond_to? callback
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
yield self if block_given?
|
23
|
+
end
|
24
|
+
|
25
|
+
def close_cb(&block)
|
26
|
+
cb = Callback.new(@callbacks, &block)
|
27
|
+
@callbacks[:close_cb] = cb
|
28
|
+
@state[:close_cb] = cb
|
29
|
+
end
|
30
|
+
|
31
|
+
def verify_cb
|
32
|
+
cb = ::FFI::Function.new(:int, [::RubyTls::State.ptr, :string]) do |state, cert|
|
33
|
+
begin
|
34
|
+
yield(cert) == true ? 1 : 0
|
35
|
+
rescue
|
36
|
+
# TODO:: Provide some debugging output
|
37
|
+
0
|
38
|
+
end
|
39
|
+
end
|
40
|
+
@callbacks[:verify_cb] = cb
|
41
|
+
@state[:verify_cb] = cb
|
42
|
+
end
|
43
|
+
|
44
|
+
def dispatch_cb(&block)
|
45
|
+
cb = DataCallback.new(@callbacks, &block)
|
46
|
+
@callbacks[:dispatch_cb] = cb
|
47
|
+
@state[:dispatch_cb] = cb
|
48
|
+
end
|
49
|
+
|
50
|
+
def transmit_cb(&block)
|
51
|
+
cb = DataCallback.new(@callbacks, &block)
|
52
|
+
@callbacks[:transmit_cb] = cb
|
53
|
+
@state[:transmit_cb] = cb
|
54
|
+
end
|
55
|
+
|
56
|
+
def handshake_cb(&block)
|
57
|
+
cb = Callback.new(@callbacks, &block)
|
58
|
+
@callbacks[:handshake_cb] = cb
|
59
|
+
@state[:handshake_cb] = cb
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
def start(args = {})
|
64
|
+
return if @started
|
65
|
+
|
66
|
+
server, priv_key, cert_chain, verify_peer = args.values_at(:server, :private_key_file, :cert_chain_file, :verify_peer)
|
67
|
+
[priv_key, cert_chain].each do |file|
|
68
|
+
next if file.nil? or file.empty?
|
69
|
+
raise FileNotFoundException,
|
70
|
+
"Could not find #{file} to start tls" unless File.exists? file
|
71
|
+
end
|
72
|
+
@started = true
|
73
|
+
::RubyTls.start_tls(@state, server || false, priv_key || '', cert_chain || '', verify_peer || !!@callbacks[:verify_cb])
|
74
|
+
end
|
75
|
+
|
76
|
+
def encrypt(data)
|
77
|
+
::RubyTls.encrypt_data(@state, data, data.length)
|
78
|
+
end
|
79
|
+
|
80
|
+
def decrypt(data)
|
81
|
+
::RubyTls.decrypt_data(@state, data, data.length)
|
82
|
+
end
|
83
|
+
|
84
|
+
def cleanup
|
85
|
+
::RubyTls.cleanup(@state)
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
protected
|
90
|
+
|
91
|
+
|
92
|
+
class Callback < ::FFI::Function
|
93
|
+
#
|
94
|
+
# Creates a new Parser callback.
|
95
|
+
#
|
96
|
+
def self.new(callbacks)
|
97
|
+
super(:void, [::RubyTls::State.ptr]) do |state|
|
98
|
+
begin
|
99
|
+
yield
|
100
|
+
rescue => e
|
101
|
+
# shutdown the connection on error
|
102
|
+
# TODO:: Provide some debugging output
|
103
|
+
callbacks[:close_cb].call state
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
class DataCallback < ::FFI::Function
|
110
|
+
def self.new(callbacks)
|
111
|
+
super(:void, [::RubyTls::State.ptr, :pointer, :int]) do |state, buffer, length|
|
112
|
+
begin
|
113
|
+
data = buffer.get_bytes(0, length)
|
114
|
+
yield(data)
|
115
|
+
rescue => e
|
116
|
+
# shutdown the connection on error
|
117
|
+
# TODO:: Provide some debugging output
|
118
|
+
callbacks[:close_cb].call state
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|