libtls 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.yardopts +3 -0
- data/Gemfile +4 -0
- data/LICENSE +13 -0
- data/README.md +279 -0
- data/Rakefile +9 -0
- data/lib/libtls.rb +9 -0
- data/lib/libtls/client.rb +195 -0
- data/lib/libtls/config.rb +112 -0
- data/lib/libtls/exn.rb +22 -0
- data/lib/libtls/raw.rb +759 -0
- data/lib/libtls/server.rb +128 -0
- data/lib/libtls/version.rb +8 -0
- data/libtls.gemspec +30 -0
- data/spec/fixtures/mike-burns.pem +116 -0
- data/spec/fixtures/theca.pem +13 -0
- data/spec/fixtures/thecert.crt +13 -0
- data/spec/fixtures/thecsr.csr +11 -0
- data/spec/fixtures/thekey.key +15 -0
- data/spec/fixtures/thekey.key.protected +18 -0
- data/spec/oo/client_spec.rb +28 -0
- data/spec/oo/server_spec.rb +75 -0
- data/spec/support/fixtures.rb +10 -0
- metadata +135 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1566c4cd86920d7e089b2087c3b98f62b5d43217
|
4
|
+
data.tar.gz: 3618c5cc4bcd47205a61664c8b52bbeba6bc91df
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fc0d68830f69516be58bf616d81ab44b6bad1e30c9e6882b96dca089fe8a3bf8d6784e45a501098770fecde8922637a3ba6cac7aee083e4a4f1b573df37da50f
|
7
|
+
data.tar.gz: 74d0efa0af199bb1f938e8ee6a70a69d55915108d82c7a3d638c01750ee9d1fa7edb4c8ed66f9071497575db15d43d69e7fbf31ca842e8d5896661eca9731701
|
data/.gitignore
ADDED
data/.yardopts
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright (c) 2015 Mike Burns <mike@mike-burns.com>
|
2
|
+
|
3
|
+
Permission to use, copy, modify, and distribute this software for any
|
4
|
+
purpose with or without fee is hereby granted, provided that the above
|
5
|
+
copyright notice and this permission notice appear in all copies.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
8
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
9
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
10
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
11
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
12
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
13
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,279 @@
|
|
1
|
+
# libtls for Ruby
|
2
|
+
|
3
|
+
This is a set of libtls bindings for Ruby, plus a nice object-oriented layer
|
4
|
+
atop the bindings.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
This gem depends on the libtls library. Make sure you either run OpenBSD or
|
9
|
+
have [libressl-portable] installed.
|
10
|
+
|
11
|
+
Once libtls itself is installed, add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'libtls'
|
15
|
+
```
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install libtls
|
24
|
+
|
25
|
+
[libressl-portable]: http://www.libressl.org/releases.html
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
This library provides the API on two levels: the raw C functions, and a nice
|
30
|
+
object-oriented layer atop it.
|
31
|
+
|
32
|
+
### Raw
|
33
|
+
|
34
|
+
The raw functions are as follows; see `tls_init`(3) for more information on what
|
35
|
+
they do:
|
36
|
+
|
37
|
+
- `LibTLS::Raw.tls_init`
|
38
|
+
- `LibTLS::Raw.tls_error`
|
39
|
+
- `LibTLS::Raw.tls_config_new`
|
40
|
+
- `LibTLS::Raw.tls_config_free`
|
41
|
+
- `LibTLS::Raw.tls_config_parse_protocols`
|
42
|
+
- `LibTLS::Raw.tls_config_set_ca_file`
|
43
|
+
- `LibTLS::Raw.tls_config_set_ca_path`
|
44
|
+
- `LibTLS::Raw.tls_config_set_ca_mem`
|
45
|
+
- `LibTLS::Raw.tls_config_set_cert_file`
|
46
|
+
- `LibTLS::Raw.tls_config_set_cert_mem`
|
47
|
+
- `LibTLS::Raw.tls_config_set_ciphers`
|
48
|
+
- `LibTLS::Raw.tls_config_set_dheparams`
|
49
|
+
- `LibTLS::Raw.tls_config_set_ecdhecurve`
|
50
|
+
- `LibTLS::Raw.tls_config_set_key_file`
|
51
|
+
- `LibTLS::Raw.tls_config_set_key_mem`
|
52
|
+
- `LibTLS::Raw.tls_config_set_protocols`
|
53
|
+
- `LibTLS::Raw.tls_config_set_verify_depth`
|
54
|
+
- `LibTLS::Raw.tls_config_clear_keys`
|
55
|
+
- `LibTLS::Raw.tls_config_insecure_noverifycert`
|
56
|
+
- `LibTLS::Raw.tls_config_insecure_noverifyname`
|
57
|
+
- `LibTLS::Raw.tls_config_verify`
|
58
|
+
- `LibTLS::Raw.tls_load_file`
|
59
|
+
- `LibTLS::Raw.tls_client`
|
60
|
+
- `LibTLS::Raw.tls_server`
|
61
|
+
- `LibTLS::Raw.tls_configure`
|
62
|
+
- `LibTLS::Raw.tls_reset`
|
63
|
+
- `LibTLS::Raw.tls_close`
|
64
|
+
- `LibTLS::Raw.tls_free`
|
65
|
+
- `LibTLS::Raw.tls_connect`
|
66
|
+
- `LibTLS::Raw.tls_connect_fds`
|
67
|
+
- `LibTLS::Raw.tls_connect_servername`
|
68
|
+
- `LibTLS::Raw.tls_connect_socket`
|
69
|
+
- `LibTLS::Raw.tls_accept_fds`
|
70
|
+
- `LibTLS::Raw.tls_accept_socket`
|
71
|
+
- `LibTLS::Raw.tls_read`
|
72
|
+
- `LibTLS::Raw.tls_write`
|
73
|
+
|
74
|
+
Of particular note are those functions which take a pointer (`tls_read`,
|
75
|
+
`tls_write`, `tls_accept_socket`, and others). These must have an instance of
|
76
|
+
`FFI::MemoryPointer` passed to them:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
FFI::MemoryPointer.new(:size_t) do |outlen|
|
80
|
+
FFI::MemoryPointer.new(:uchar, 1024, true) do |buf|
|
81
|
+
|
82
|
+
ret = LibTLS::Raw.tls_read(client, buf, 1024, outlen)
|
83
|
+
|
84
|
+
if ret < 0
|
85
|
+
raise "tls_read: #{LibTLS::Raw.tls_error(client)}"
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
90
|
+
```
|
91
|
+
|
92
|
+
Additionally, instance of Ruby's `Socket` object must be converted to their
|
93
|
+
file descriptor before interfacing with the C function. The `tls_accept_socket`
|
94
|
+
function combines the `FFI::MemoryPointer` requirement with this file
|
95
|
+
descriptor requirement:
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
cctx_ptr = FFI::MemoryPointer.new(:pointer)
|
99
|
+
|
100
|
+
if tls_accept_socket(server, cctx_ptr, socket.fileno) == -1
|
101
|
+
raise "tls_accept_socket: #{LibTLS::Raw.tls_error(server)}"
|
102
|
+
end
|
103
|
+
|
104
|
+
cctx = cctx_ptr.read_pointer
|
105
|
+
```
|
106
|
+
|
107
|
+
Constants from `tls.h` are manually re-exposed under the `LibTLS::Raw`
|
108
|
+
namespace:
|
109
|
+
|
110
|
+
- `LibTLS::Raw::TLS_API`
|
111
|
+
- `LibTLS::Raw::TLS_PROTOCOL_TLSv1_0`
|
112
|
+
- `LibTLS::Raw::TLS_PROTOCOL_TLSv1_1`
|
113
|
+
- `LibTLS::Raw::TLS_PROTOCOL_TLSv1_2`
|
114
|
+
- `LibTLS::Raw::TLS_PROTOCOL_TLSv1`
|
115
|
+
- `LibTLS::Raw::TLS_PROTOCOLS_ALL`
|
116
|
+
- `LibTLS::Raw::TLS_PROTOCOLS_DEFAULT`
|
117
|
+
- `LibTLS::Raw::TLS_READ_AGAIN`
|
118
|
+
- `LibTLS::Raw::TLS_WRITE_AGAIN`
|
119
|
+
|
120
|
+
### Object-Oriented Wrapper
|
121
|
+
|
122
|
+
An object-oriented wrapper is provided. Here is an example of a client:
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
# Get the contents of the Web page hosted at https://#{hostname}:443#{path} .
|
126
|
+
def get(hostname, path)
|
127
|
+
# The return value: nil, or a string.
|
128
|
+
content = nil
|
129
|
+
|
130
|
+
# TLS configuration. The key is formed from the series of tls_config_set_*
|
131
|
+
# functions; the value is either the scalar value (int or string), or an
|
132
|
+
# array of the multiple values. For example, ca_mem takes an array with the
|
133
|
+
# FFI::MemoryPointer and the length of that pointer.
|
134
|
+
config = {
|
135
|
+
ciphers: "DES-CBC3-SHA",
|
136
|
+
protocols: LibTLS::Raw::TLS_PROTOCOLS_ALL
|
137
|
+
}
|
138
|
+
|
139
|
+
# Create a new libtls client. The block is then immediately run, and then the
|
140
|
+
# memory free'd.
|
141
|
+
LibTLS::Client.new(configure: config) do |client|
|
142
|
+
# Connect to the server on port 443. When the block finishes, disconnect.
|
143
|
+
content = client.connect("mike-burns.com", 443) do |c|
|
144
|
+
# Send a string to the server; in this case, a HTTP request.
|
145
|
+
c.write(http_get(hostname, path))
|
146
|
+
# Read all the data from the server, and return it. The return value of
|
147
|
+
# this block is the return value of Client#connect.
|
148
|
+
c.read
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Return the content.
|
153
|
+
content
|
154
|
+
end
|
155
|
+
|
156
|
+
# Generate a HTTP request string.
|
157
|
+
def http_get(hostname, path)
|
158
|
+
["GET #{path} HTTP/1.1",
|
159
|
+
"User-Agent: libtls.rb/0.1",
|
160
|
+
"Host: #{hostname}"].join("\r\n") +
|
161
|
+
"\r\n"
|
162
|
+
end
|
163
|
+
```
|
164
|
+
|
165
|
+
And here is an example of a simple echo server:
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
# Reply to the socket's clients with their own string.
|
169
|
+
def echo_server(socket)
|
170
|
+
# Encrypt communications using the key and cert as generated by e.g.
|
171
|
+
# LibreSSL.
|
172
|
+
config = {
|
173
|
+
key_file: "thekey.key",
|
174
|
+
cert_file: "thecert.crt"
|
175
|
+
}
|
176
|
+
|
177
|
+
# Create and configure a new server object. The block is then immediately
|
178
|
+
# run, and then the memory is free'd.
|
179
|
+
LibTLS::Server.new(configure: config) do |server|
|
180
|
+
# Block until a client connects on client_socket.
|
181
|
+
client_socket, _ = socket.accept
|
182
|
+
|
183
|
+
# Loop forever; this allows another client to connect after this one.
|
184
|
+
loop do
|
185
|
+
# Handle the TLS handshake on the client socket. This takes a block,
|
186
|
+
# which is run immediately after the handshake has completed
|
187
|
+
# successfully. After the block finishes, disconnect and clean up. The
|
188
|
+
# block takes an opened client object.
|
189
|
+
server.accept(client_socket) do |c|
|
190
|
+
# Loop so that the client can write until they disconnect.
|
191
|
+
loop do
|
192
|
+
# Read the entirety of the client's string.
|
193
|
+
str = c.read
|
194
|
+
# Write exactly what the client sent.
|
195
|
+
c.write(str)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
```
|
202
|
+
|
203
|
+
The underlying `struct tls *` object is exposed through the `#ctx` method; it
|
204
|
+
can be passed to any `LibTLS::Raw` method, for example.
|
205
|
+
|
206
|
+
These methods can raise instances of `LibTLS::UnknownCError` and
|
207
|
+
`LibTLS::CError`. Instances of the first are raised when we do not have access
|
208
|
+
to the underlying issue, and instances of the second attempt to include the
|
209
|
+
error string from libtls.
|
210
|
+
|
211
|
+
## Contributing
|
212
|
+
|
213
|
+
As contributors and maintainers of this project, we will respect all people
|
214
|
+
who contribute in any fashion. We are committed to making participation in this
|
215
|
+
project a harassment-free experience for everyone, regardless of who they are.
|
216
|
+
|
217
|
+
The project maintainers have the right and responsibility to remove, edit, or
|
218
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
219
|
+
that are not aligned to this code of conduct. Project maintainers who do not
|
220
|
+
follow the code of conduct may be removed from the project team.
|
221
|
+
|
222
|
+
Instances of unacceptable behavior may be reported by [opening an
|
223
|
+
issue][issues] or contacting [Mike Burns](mailto:mike@mike-burns.com)
|
224
|
+
([PGP key][Mike PGP key]).
|
225
|
+
|
226
|
+
[issues]: https://github.com/mike-burns/libtls.rb/issues
|
227
|
+
[Mike PGP key]: http://pgp.mit.edu/pks/lookup?op=get&search=0x3E6761F72846B014
|
228
|
+
|
229
|
+
### To contribute a feature
|
230
|
+
|
231
|
+
1. Fork it ( https://github.com/mike-burns/libtls.rb/fork )
|
232
|
+
2. Make sure the tests pass (`rake`)
|
233
|
+
3. Create your feature branch (`git checkout -b my-new-feature`)
|
234
|
+
4. Commit your changes (`git commit -am 'Add some feature'`)
|
235
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
236
|
+
6. Make sure the tests pass (`rake`)
|
237
|
+
7. Make sure documentation is complete (`yard`)
|
238
|
+
8. Create a new Pull Request
|
239
|
+
|
240
|
+
*Feature requests without patches will be closed*.
|
241
|
+
|
242
|
+
### To report a security issue
|
243
|
+
|
244
|
+
If the issue should be kept quiet for security reasons, email
|
245
|
+
[Mike Burns](mailto:mike@mike-burns.com) directly. His PGP key id is
|
246
|
+
[0x2846b014][Mike PGP key], fingerprint:
|
247
|
+
|
248
|
+
5FD8 2CE6 A646 3285 538F
|
249
|
+
C3A5 3E67 61F7 2846 B014
|
250
|
+
|
251
|
+
## Credits
|
252
|
+
|
253
|
+
libtls for Ruby is by [Mike Burns]. It is released under the
|
254
|
+
[ISC license][LICENSE].
|
255
|
+
|
256
|
+
It would have been impossible to make this library so quickly without the
|
257
|
+
knowledge gained on [erltls] with [Rebecca Meritz].
|
258
|
+
|
259
|
+
GNU help was provided by [Matt Horan].
|
260
|
+
|
261
|
+
The [ffi] gem has also proven crucial to this project; thanks to
|
262
|
+
[Wayne Meissner, et al.][ffi credits], for their amazing work on that.
|
263
|
+
|
264
|
+
The code of conduct is adapted from the [Contributor Covenant],
|
265
|
+
[version 1.1.0][coc110].
|
266
|
+
|
267
|
+
[Donate to the OpenBSD Foundation][donate]. Without them, none of this would
|
268
|
+
exist.
|
269
|
+
|
270
|
+
[Mike Burns]: https://mike-burns.com
|
271
|
+
[Rebecca Meritz]: http://rebecca.meritz.com/
|
272
|
+
[Matt Horan]: https://matthoran.com/
|
273
|
+
[LICENSE]: LICENSE
|
274
|
+
[donate]: http://www.openbsdfoundation.org/donations.html
|
275
|
+
[ffi]: https://github.com/ffi/ffi/wiki
|
276
|
+
[ffi credits]: https://github.com/ffi/ffi/#credits
|
277
|
+
[erltls]: https://github.com/meritz-burns/erltls
|
278
|
+
[Contributor Covenant]: http://contributor-covenant.org
|
279
|
+
[coc110]: http://contributor-covenant.org/version/1/1/0/
|
data/Rakefile
ADDED
data/lib/libtls.rb
ADDED
@@ -0,0 +1,195 @@
|
|
1
|
+
require 'libtls/config'
|
2
|
+
require 'libtls/raw'
|
3
|
+
|
4
|
+
module LibTLS
|
5
|
+
##
|
6
|
+
# This class represents a TLS client connecting to a server. Here is a sample
|
7
|
+
# HTTPS session; this #get method will produce the content at the specified
|
8
|
+
# path on the hostname:
|
9
|
+
#
|
10
|
+
# def get(hostname, path)
|
11
|
+
# content = nil
|
12
|
+
# config = { ca_file: '/etc/ssl/cert.pem' }
|
13
|
+
#
|
14
|
+
# LibTLS::Client.new(configure: config) do |client|
|
15
|
+
# content = client.connect("mike-burns.com", 443) do |c|
|
16
|
+
# c.write(http_get(hostname, path))
|
17
|
+
# c.read
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# content
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# def http_get(hostname, path)
|
25
|
+
# ["GET #{path} HTTP/1.1",
|
26
|
+
# "User-Agent: libtls.rb/0.1",
|
27
|
+
# "Host: #{hostname}"].join("\r\n") +
|
28
|
+
# "\r\n"
|
29
|
+
# end
|
30
|
+
class Client
|
31
|
+
##
|
32
|
+
# The FFI wrapper around the struct tls object
|
33
|
+
#
|
34
|
+
# This is only useful for calling any of the {LibTLS::Raw} methods.
|
35
|
+
attr_reader :ctx
|
36
|
+
|
37
|
+
##
|
38
|
+
# Construct a new [Client] instance
|
39
|
+
#
|
40
|
+
# Once constructed, it runs the block. When the block finishes, it calls
|
41
|
+
# {#finish}.
|
42
|
+
#
|
43
|
+
# @param configure [Hash] a mapping from setting name to value. The setting
|
44
|
+
# name is any of {LibTLS::Config::VALID_SET_CONFIGS}; the value is either a
|
45
|
+
# scalar value passed through to the C function, or an array of values. For
|
46
|
+
# example:
|
47
|
+
# { ca_file: 'ca.pem', key_mem: [key_ptr, 48] }
|
48
|
+
# @yieldparam [Client] self an initialized and configured instance of self
|
49
|
+
# @raise [LibTLS::UnknownCError] if +tls_init+ or +tls_client+ fails
|
50
|
+
# @raise [LibTLS::CError] if +tls_configure+ fails
|
51
|
+
def initialize(configure:, &block)
|
52
|
+
if LibTLS::Raw.tls_init < 0
|
53
|
+
raise LibTLS::UnknownCError, "tls_init"
|
54
|
+
end
|
55
|
+
|
56
|
+
@config = Config.new(configure)
|
57
|
+
|
58
|
+
if (@ctx = LibTLS::Raw.tls_client).null?
|
59
|
+
raise LibTLS::UnknownCError, "tls_client"
|
60
|
+
end
|
61
|
+
|
62
|
+
if LibTLS::Raw::tls_configure(ctx, @config.as_raw) < 0
|
63
|
+
raise LibTLS::CError, "tls_configure: #{LibTLS::Raw.tls_error(ctx)}"
|
64
|
+
end
|
65
|
+
|
66
|
+
if block
|
67
|
+
begin
|
68
|
+
block.call(self)
|
69
|
+
ensure
|
70
|
+
self.finish
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
##
|
76
|
+
# Open a connection with the server
|
77
|
+
#
|
78
|
+
# This method negotiates the TLS connection with the +hostname+, at the
|
79
|
+
# +port+. Once connected, it passes the connected client to the block. Once
|
80
|
+
# the block finishes, it calls {OpenedClient#close} on the connection.
|
81
|
+
#
|
82
|
+
# @param hostname [String] the server to connect to, as an IPv4 address, an
|
83
|
+
# IPv6 address, or anything that can be resolved by +getaddrinfo+.
|
84
|
+
# @param port [#to_s] the port on the server to connect to
|
85
|
+
# @yieldparam [OpenedClient] client a connected client
|
86
|
+
# @raise [LibTLS::CError] if the +tls_connect+ fails
|
87
|
+
# @return the result of the block
|
88
|
+
def connect(hostname, port, &block)
|
89
|
+
opened_client = nil
|
90
|
+
|
91
|
+
begin
|
92
|
+
if LibTLS::Raw.tls_connect(ctx, hostname, port.to_s) < 0
|
93
|
+
raise LibTLS::CError, "tls_connect: #{LibTLS::Raw.tls_error(ctx)}"
|
94
|
+
end
|
95
|
+
|
96
|
+
opened_client = OpenedClient.new(ctx)
|
97
|
+
block.call(opened_client)
|
98
|
+
ensure
|
99
|
+
opened_client && opened_client.close
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
##
|
104
|
+
# Release any memory held on to by the C library
|
105
|
+
#
|
106
|
+
# This method must be called either implicitly by passing a block to
|
107
|
+
# {#initialize}, or explicitly by you.
|
108
|
+
def finish
|
109
|
+
@config.free
|
110
|
+
LibTLS::Raw.tls_free(ctx)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
##
|
117
|
+
# A TLS client connected to a server
|
118
|
+
#
|
119
|
+
# This class must be instantiated only by {LibTLS::Client#connect} and
|
120
|
+
# {LibTLS::Server#accept}.
|
121
|
+
#
|
122
|
+
# When finished, {#close} must be called. This is implicitly handled for you by
|
123
|
+
# passing a block to the methods mentioned above.
|
124
|
+
class OpenedClient
|
125
|
+
READ_LEN = 1024
|
126
|
+
private_constant :READ_LEN
|
127
|
+
|
128
|
+
##
|
129
|
+
# The FFI wrapper around the struct tls object
|
130
|
+
#
|
131
|
+
# This is only useful for calling any of the {LibTLS::Raw} methods.
|
132
|
+
attr_reader :ctx
|
133
|
+
|
134
|
+
##
|
135
|
+
# @api private
|
136
|
+
def initialize(ctx)
|
137
|
+
@ctx = ctx
|
138
|
+
end
|
139
|
+
|
140
|
+
##
|
141
|
+
# Close this connection
|
142
|
+
#
|
143
|
+
# This method must be called either implicitly by passing a block to
|
144
|
+
# {LibTLS::Client#connect} or {LibTLS::Server#accept}, or explicitly by you.
|
145
|
+
def close
|
146
|
+
if LibTLS::Raw.tls_close(ctx) < 0
|
147
|
+
raise LibTLS::CError, "tls_close: #{LibTLS::Raw.tls_error(ctx)}"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
##
|
152
|
+
# Write the string to the connection
|
153
|
+
#
|
154
|
+
# @param [String] str the string to write
|
155
|
+
# @raise [LibTLS::CError] if +tls_write+ fails
|
156
|
+
def write(str)
|
157
|
+
FFI::MemoryPointer.new(:size_t) do |outlen|
|
158
|
+
FFI::MemoryPointer.new(:uchar, str.length + 1) do |str_ptr|
|
159
|
+
str_ptr.put_string(0, str)
|
160
|
+
|
161
|
+
if LibTLS::Raw.tls_write(ctx, str_ptr, str.length, outlen) < 0
|
162
|
+
raise LibTLS::CError, "tls_write: #{LibTLS::Raw.tls_error(ctx)}"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
##
|
169
|
+
# Read a string from the connection
|
170
|
+
#
|
171
|
+
# @raise [LibTLS::CError] if +tls_read+ fails
|
172
|
+
# @return [String] the accumulated buffer
|
173
|
+
def read
|
174
|
+
str = ""
|
175
|
+
|
176
|
+
FFI::MemoryPointer.new(:size_t) do |outlen|
|
177
|
+
FFI::MemoryPointer.new(:uchar, READ_LEN, true) do |buf|
|
178
|
+
loop do
|
179
|
+
if LibTLS::Raw.tls_read(ctx, buf, READ_LEN, outlen) < 0
|
180
|
+
raise LibTLS::CError, "tls_read: #{LibTLS::Raw.tls_error(ctx)}"
|
181
|
+
end
|
182
|
+
|
183
|
+
str += buf.get_string(0, outlen.get_int(0))
|
184
|
+
|
185
|
+
if READ_LEN > outlen.get_int(0)
|
186
|
+
break
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
str
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|