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
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'libtls/raw'
|
2
|
+
require 'libtls/exn'
|
3
|
+
|
4
|
+
module LibTLS
|
5
|
+
##
|
6
|
+
# A TLS configuration
|
7
|
+
#
|
8
|
+
# This object is an abstraction over the libtls configuration. It can be used
|
9
|
+
# as a shorthand for configuring the struct tls context.
|
10
|
+
#
|
11
|
+
# config = LibTLS::Config.new(
|
12
|
+
# ca_path: '/etc/ssl',
|
13
|
+
# key_mem: [key_ptr, 512]
|
14
|
+
# )
|
15
|
+
# LibTLS::Raw.tls_configure(ctx, config.as_raw)
|
16
|
+
# config.free
|
17
|
+
class Config
|
18
|
+
##
|
19
|
+
# Keys that can be configured
|
20
|
+
#
|
21
|
+
# This is derived from the +tls_config_set_*+ functions in {LibTLS::Raw}.
|
22
|
+
VALID_SET_CONFIGS = %i(
|
23
|
+
ca_file ca_path ca_mem cert_file cert_mem ciphers dheparams ecdhecurve
|
24
|
+
key_file key_mem protocols verify_depth
|
25
|
+
)
|
26
|
+
|
27
|
+
##
|
28
|
+
# Return a new instance of Config
|
29
|
+
#
|
30
|
+
# @param [Hash] config_hash the Ruby representation of the configuration. The
|
31
|
+
# keys are any of {VALID_SET_CONFIGS}; the value is either a scalar value,
|
32
|
+
# or an array. The array is splatted into the appropriate C function.
|
33
|
+
#
|
34
|
+
# @option config_hash [String] ca_file The filename used to load a file containing
|
35
|
+
# the root certificates. (_Client_)
|
36
|
+
# @option config_hash [String] ca_path The path (directory) which should be
|
37
|
+
# searched for root certificates. (_Client_)
|
38
|
+
# @option config_hash [[FFI::Pointer, Fixnum]] ca_mem Set the root certificates
|
39
|
+
# directly from memory. (_Client_)
|
40
|
+
# @option config_hash [String] cert_file Set file from which the public
|
41
|
+
# certificate will be read. (_Client_ _and_ _server_)
|
42
|
+
# @option config_hash [[FFI::Pointer, Fixnum]] cert_mem Set the public
|
43
|
+
# certificate directly from memory. (_Client_ _and_ _server_)
|
44
|
+
# @option config_hash [String] ciphers Set the list of ciphers that may be
|
45
|
+
# used. (_Client_ _and_ _server_)
|
46
|
+
# @option config_hash [String] dheparams Set the dheparams option to either
|
47
|
+
# "none" (0), "auto" (-1), or "legacy" (1024). The default is "none".
|
48
|
+
# (_Server_)
|
49
|
+
# @option config_hash [String] ecdhecurve Set the ecdhecurve option to one of
|
50
|
+
# "none" (+NID_undef+), "auto" (-1), or any NID value understood by
|
51
|
+
# OBJ_txt2nid (3). (_Server_)
|
52
|
+
# @option config_hash [String] keyfile Set the file from which the private
|
53
|
+
# key will be read. (_Server_)
|
54
|
+
# @option config_hash [[FFI::Pointer, Fixnum]] key_mem Directly set the
|
55
|
+
# private key from memory. (_Server_)
|
56
|
+
# @option config_hash [Fixnum] protocols Sets which versions of the protocol
|
57
|
+
# may be used, as documented in {LibTLS::Raw#tls_config_set_protocols}.
|
58
|
+
# (_Client_ _and_ _server_)
|
59
|
+
# @option config_hash [Fixnum] verify_depth Set the verify depth as
|
60
|
+
# documented under SSL_CTX_set_verify_depth(3). (_Client_)
|
61
|
+
def initialize(config_hash)
|
62
|
+
@config_hash = config_hash
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# Convert this object into the C representation
|
67
|
+
#
|
68
|
+
# This builds a struct tls_config pointer, sets the values on it as dictated
|
69
|
+
# by the hash passed in, and returns the struct tls_config pointer.
|
70
|
+
#
|
71
|
+
# The return value must be freed using {#free}.
|
72
|
+
#
|
73
|
+
# @return [FFI::Pointer] the completed struct tls_config pointer
|
74
|
+
# @raise [LibTLS::UnknownCError] if +tls_config_new+ or the appropriate
|
75
|
+
# +tls_config_set_*+ fails
|
76
|
+
def as_raw
|
77
|
+
@raw_config ||= buld_raw_config
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Release any memory held on to by the C library
|
82
|
+
#
|
83
|
+
# This method must be called when finished.
|
84
|
+
def free
|
85
|
+
LibTLS::Raw.tls_config_free(as_raw)
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def buld_raw_config
|
91
|
+
if (raw = LibTLS::Raw.tls_config_new).null?
|
92
|
+
raise LibTLS::UnknownCError, "tls_config_new"
|
93
|
+
end
|
94
|
+
|
95
|
+
valid_config_hash.each do |key, value|
|
96
|
+
ret = LibTLS::Raw.send("tls_config_set_#{key}", raw, *value)
|
97
|
+
|
98
|
+
if ret && ret < 0
|
99
|
+
raise LibTLS::UnknownCError, "tls_config_set_#{key}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
raw
|
104
|
+
end
|
105
|
+
|
106
|
+
def valid_config_hash
|
107
|
+
@config_hash.select do |key, value|
|
108
|
+
VALID_SET_CONFIGS.include?(key)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
data/lib/libtls/exn.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module LibTLS
|
2
|
+
##
|
3
|
+
# An unknown error occured in the libtls library
|
4
|
+
#
|
5
|
+
# This exception is raised when a non-TLS issue occurs in the libtls library.
|
6
|
+
# If possible, it might be useful to inspect +errno+ when you rescue this
|
7
|
+
# exception.
|
8
|
+
class UnknownCError < RuntimeError
|
9
|
+
##
|
10
|
+
# A description of the error
|
11
|
+
#
|
12
|
+
# This description contains the C function name.
|
13
|
+
def to_s
|
14
|
+
"#{super.to_s} failed"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
##
|
19
|
+
# A known error occured in the libtls library
|
20
|
+
class CError < RuntimeError
|
21
|
+
end
|
22
|
+
end
|
data/lib/libtls/raw.rb
ADDED
@@ -0,0 +1,759 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module LibTLS
|
4
|
+
##
|
5
|
+
# Direct access to C functions
|
6
|
+
#
|
7
|
+
# This module encapsulates the communication between Ruby and the C libtls
|
8
|
+
# library.
|
9
|
+
#
|
10
|
+
# We recommend that you consider the object-oriented API in {LibTLS::Client}
|
11
|
+
# and {LibTLS::Server} before reaching for these functions. However, not all
|
12
|
+
# functions are accessible via those two classes.
|
13
|
+
#
|
14
|
+
# The {LibTLS::Server}, {LibTLS::Client}, and {LibTLS::OpenedClient}
|
15
|
+
# instances provide access to the +FFI::Pointer+ that is used by functions in
|
16
|
+
# this module, so that you can mostly use the OO interface but directly access
|
17
|
+
# the C functions when needed.
|
18
|
+
#
|
19
|
+
# Using functions from here means that you are familiar with the tls_init(3)
|
20
|
+
# man page and the +FFI::MemoryPointer+ class.
|
21
|
+
#
|
22
|
+
# Much of the documentation in this file is taken from the tls_init(3) man
|
23
|
+
# page. Such documentation is copyright 2014 Ted Unangst, licensed under the
|
24
|
+
# ISC license.
|
25
|
+
module Raw
|
26
|
+
extend FFI::Library
|
27
|
+
|
28
|
+
ffi_lib "libtls.so"
|
29
|
+
|
30
|
+
##
|
31
|
+
# The version of the libtls API.
|
32
|
+
TLS_API = 20141031
|
33
|
+
|
34
|
+
##
|
35
|
+
# Select the TLS 1.0 protocol
|
36
|
+
TLS_PROTOCOL_TLSv1_0 = (1 << 1)
|
37
|
+
##
|
38
|
+
# Select the TLS 1.1 protocol
|
39
|
+
TLS_PROTOCOL_TLSv1_1 = (1 << 2)
|
40
|
+
##
|
41
|
+
# Select the TLS 1.2 protocol
|
42
|
+
TLS_PROTOCOL_TLSv1_2 = (1 << 3)
|
43
|
+
##
|
44
|
+
# Select any TLS 1.x protocol
|
45
|
+
TLS_PROTOCOL_TLSv1 = \
|
46
|
+
TLS_PROTOCOL_TLSv1_0 | TLS_PROTOCOL_TLSv1_1 | TLS_PROTOCOL_TLSv1_2
|
47
|
+
|
48
|
+
##
|
49
|
+
# Select any TLS protocol of any version
|
50
|
+
TLS_PROTOCOLS_ALL = TLS_PROTOCOL_TLSv1
|
51
|
+
##
|
52
|
+
# Select the default, suggested TLS protocol
|
53
|
+
#
|
54
|
+
# Do not use any protocol except this one unless you understand why you are
|
55
|
+
# doing so.
|
56
|
+
TLS_PROTOCOLS_DEFAULT = TLS_PROTOCOL_TLSv1_2
|
57
|
+
|
58
|
+
##
|
59
|
+
# A read operation is necessary to continue
|
60
|
+
TLS_READ_AGAIN = -2
|
61
|
+
##
|
62
|
+
# A write operation is necessary to continue
|
63
|
+
TLS_WRITE_AGAIN = -3
|
64
|
+
|
65
|
+
##
|
66
|
+
# @!method tls_init()
|
67
|
+
#
|
68
|
+
# Initialize the libtls library
|
69
|
+
#
|
70
|
+
# The +tls_init+ function should be called once before any function is used.
|
71
|
+
# It may be called more than once, but not concurrently.
|
72
|
+
#
|
73
|
+
# @return [Fixnum] 0 on success, -1 on error
|
74
|
+
attach_function :tls_init, [], :int
|
75
|
+
|
76
|
+
##
|
77
|
+
# @!method tls_error(ctx)
|
78
|
+
#
|
79
|
+
# Produce the error message on the context
|
80
|
+
#
|
81
|
+
# The +tls_error+ function may be used to retrieve a string containing more
|
82
|
+
# information about the most recent error.
|
83
|
+
#
|
84
|
+
# @param ctx [FFI::Pointer] the TLS context
|
85
|
+
# @return [String] the error message for the most recent error
|
86
|
+
attach_function :tls_error, [:pointer], :string
|
87
|
+
|
88
|
+
##
|
89
|
+
# @!group Create and free configuration objects
|
90
|
+
# @!method tls_config_new()
|
91
|
+
#
|
92
|
+
# Produce a new +tls_config+ context
|
93
|
+
#
|
94
|
+
# Before a connection is created, a configuration must be created. The
|
95
|
+
# +tls_config_new+ function returns a new default configuration that can be
|
96
|
+
# used for future connections. Several functions exist to change the
|
97
|
+
# options of the configuration; see below.
|
98
|
+
#
|
99
|
+
# @return [FFI::Pointer] a +tls_config+ context or +FFI::Pointer::NULL+ on
|
100
|
+
# failure. Check using +#null?+.
|
101
|
+
attach_function :tls_config_new, [], :pointer
|
102
|
+
# @!endgroup
|
103
|
+
|
104
|
+
##
|
105
|
+
# @!group Create and free configuration objects
|
106
|
+
# @!method tls_config_free(config)
|
107
|
+
#
|
108
|
+
# Free the +tls_config+ object
|
109
|
+
#
|
110
|
+
# When no more contexts are to be created, the +tls_config+ object should be
|
111
|
+
# freed by calling +tls_config_free+.
|
112
|
+
#
|
113
|
+
# @param config [FFI::Pointer] the TLS config
|
114
|
+
# @return [nil] +void+
|
115
|
+
attach_function :tls_config_free, [:pointer], :void
|
116
|
+
# @!endgroup
|
117
|
+
|
118
|
+
##
|
119
|
+
# @!method tls_config_parse_protocols(protocols, protostr)
|
120
|
+
#
|
121
|
+
# Parse a protocol string into a bitmask
|
122
|
+
#
|
123
|
+
# The +tls_config_parse_protocols+ function parses a protocol string and
|
124
|
+
# returns the corresponding value via the +protocols+ argument. This value
|
125
|
+
# can then be passed to the {#tls_config_set_protocols} function. The
|
126
|
+
# protocol string is a comma or colon separated list of keywords. Valid
|
127
|
+
# keywords are +tlsv1.0+, +tlsv1.1+, +tlsv1.2+, +all+ (all supported
|
128
|
+
# protocols), +default+ (an alias for +secure+), +legacy+ (an alias for
|
129
|
+
# +all+) and +secure+ (currently TLSv1.2 only). If a value has a negative
|
130
|
+
# prefix (in the form of a leading exclamation mark) then it is removed
|
131
|
+
# from the list of available protocols, rather than being added to it.
|
132
|
+
#
|
133
|
+
# @param protocols [FFI::Pointer] a +uint32_t+ pointer to store the parse
|
134
|
+
# result
|
135
|
+
# @param protostr [String] the protocol string
|
136
|
+
# @return [Fixnum] 0 on success, -1 on error
|
137
|
+
#
|
138
|
+
# @todo This is untested. Please {https://github.com/mike-burns/libtls.rb#contributing contribute a patch}.
|
139
|
+
attach_function :tls_config_parse_protocols, [:uint32_t, :string], :int
|
140
|
+
|
141
|
+
##
|
142
|
+
# @!group Client configuration
|
143
|
+
# @!method tls_config_set_ca_file(config, ca_file)
|
144
|
+
#
|
145
|
+
# Use the given file as the certificate authority file
|
146
|
+
#
|
147
|
+
# +tls_config_set_ca_file+ sets the filename used to load a file containing
|
148
|
+
# the root certificates.
|
149
|
+
#
|
150
|
+
# This applies to clients.
|
151
|
+
#
|
152
|
+
# @param config [FFI::Pointer] the TLS config
|
153
|
+
# @param ca_file [String] absolute path to the file containing the root
|
154
|
+
# certificates
|
155
|
+
# @return [Fixnum] 0 on success, -1 on error
|
156
|
+
attach_function :tls_config_set_ca_file, [:pointer, :string], :int
|
157
|
+
|
158
|
+
##
|
159
|
+
# @!method tls_config_set_ca_path(config, ca_path)
|
160
|
+
#
|
161
|
+
# Use the directory specified to find the root certificate file
|
162
|
+
#
|
163
|
+
# +tls_config_set_ca_path+ sets the path (directory) which should be
|
164
|
+
# searched for root certificates.
|
165
|
+
#
|
166
|
+
# This applies to clients.
|
167
|
+
#
|
168
|
+
# @param config [FFI::Pointer] the TLS config
|
169
|
+
# @param ca_path [String] absolute path to the directory containing the
|
170
|
+
# root certificates
|
171
|
+
# @return [Fixnum] 0 on success, -1 on error
|
172
|
+
#
|
173
|
+
# @todo This is untested. Please {https://github.com/mike-burns/libtls.rb#contributing contribute a patch}.
|
174
|
+
attach_function :tls_config_set_ca_path, [:pointer, :string], :int
|
175
|
+
|
176
|
+
##
|
177
|
+
# @!method tls_config_set_ca_mem(config, cert, len)
|
178
|
+
#
|
179
|
+
# Use the root certicate from memory
|
180
|
+
#
|
181
|
+
# +tls_config_set_ca_mem+ sets the root certificates directly from memory.
|
182
|
+
#
|
183
|
+
# This applies to clients.
|
184
|
+
#
|
185
|
+
# @param config [FFI::Pointer] the TLS config
|
186
|
+
# @param cert [FFI::Pointer] uint8_t pointer to the cert
|
187
|
+
# @param len [Fixnum] number of bytes in the cert
|
188
|
+
# @return [Fixnum] 0 on success, -1 on error
|
189
|
+
#
|
190
|
+
# @todo This is untested. Please {https://github.com/mike-burns/libtls.rb#contributing contribute a patch}.
|
191
|
+
attach_function :tls_config_set_ca_mem, [:pointer, :pointer, :size_t], :int
|
192
|
+
# @!endgroup
|
193
|
+
|
194
|
+
##
|
195
|
+
# @!group Client and server configuration
|
196
|
+
# @!method tls_config_set_cert_file(config, cert_file)
|
197
|
+
#
|
198
|
+
# Use the given file as the certficate file
|
199
|
+
#
|
200
|
+
# +tls_config_set_ca_file+ sets sets file from which the public certificate
|
201
|
+
# will be read.
|
202
|
+
#
|
203
|
+
# This applies to clients and servers.
|
204
|
+
#
|
205
|
+
# @param config [FFI::Pointer] the TLS config
|
206
|
+
# @param cert_file [String] absolute path to the file containing the public
|
207
|
+
# certificate
|
208
|
+
# @return [Fixnum] 0 on success, -1 on error
|
209
|
+
attach_function :tls_config_set_cert_file, [:pointer, :string], :int
|
210
|
+
|
211
|
+
##
|
212
|
+
# @!method tls_config_set_cert_mem(config, cert, len)
|
213
|
+
#
|
214
|
+
# Use the given file as the public certificate
|
215
|
+
#
|
216
|
+
# +tls_config_set_cert_mem+ sets the public certificate directly from
|
217
|
+
# memory.
|
218
|
+
#
|
219
|
+
# This applies to clients and servers.
|
220
|
+
#
|
221
|
+
# @param config [FFI::Pointer] the TLS config
|
222
|
+
# @param cert [FFI::Pointer] uint8_t pointer to the cert
|
223
|
+
# @param len [Fixnum] number of bytes in the cert
|
224
|
+
# @return [Fixnum] 0 on success, -1 on error
|
225
|
+
#
|
226
|
+
# @todo This is untested. Please {https://github.com/mike-burns/libtls.rb#contributing contribute a patch}.
|
227
|
+
attach_function :tls_config_set_cert_mem, [:pointer, :pointer, :size_t], :int
|
228
|
+
# @!endgroup
|
229
|
+
|
230
|
+
##
|
231
|
+
# @!group Client and server configuration
|
232
|
+
# @!method tls_config_set_ciphers(config, ciphers)
|
233
|
+
#
|
234
|
+
# Use the given list of ciphers
|
235
|
+
#
|
236
|
+
# +tls_config_set_ciphers+ sets the list of ciphers that may be used.
|
237
|
+
#
|
238
|
+
# This applies to clients and servers.
|
239
|
+
#
|
240
|
+
# @param config [FFI::Pointer] the TLS config
|
241
|
+
# @param ciphers [String] a list of ciphers to use
|
242
|
+
# @return [Fixnum] 0 on success, -1 on error
|
243
|
+
attach_function :tls_config_set_ciphers, [:pointer, :string], :int
|
244
|
+
# @!endgroup
|
245
|
+
|
246
|
+
##
|
247
|
+
# @!group Server configuration
|
248
|
+
# @!method tls_config_set_dheparams(config, params)
|
249
|
+
#
|
250
|
+
# Tune the dheparams
|
251
|
+
#
|
252
|
+
# This applies to servers.
|
253
|
+
#
|
254
|
+
# @param config [FFI::Pointer] the TLS config
|
255
|
+
# @param params [String] one of "none" (0), "auto" (-1), or "legacy"
|
256
|
+
# (1024). The default is "none".
|
257
|
+
# @return [Fixnum] 0 on success, -1 on error
|
258
|
+
#
|
259
|
+
# @todo This is untested. Please {https://github.com/mike-burns/libtls.rb#contributing contribute a patch}.
|
260
|
+
attach_function :tls_config_set_dheparams, [:pointer, :string], :int
|
261
|
+
|
262
|
+
##
|
263
|
+
# @!method tls_config_set_ecdhecurve(config, name)
|
264
|
+
#
|
265
|
+
# Use the specified EC DHE curve
|
266
|
+
#
|
267
|
+
# This applies to servers.
|
268
|
+
#
|
269
|
+
# @param config [FFI::Pointer] the TLS config
|
270
|
+
# @param name one of "none" (+NID_undef+), "auto" (-1), or any NID value
|
271
|
+
# understood by OBJ_txt2nid (3).
|
272
|
+
# @return [Fixnum] 0 on success, -1 on error
|
273
|
+
#
|
274
|
+
# @todo This is untested. Please {https://github.com/mike-burns/libtls.rb#contributing contribute a patch}.
|
275
|
+
attach_function :tls_config_set_ecdhecurve, [:pointer, :string], :int
|
276
|
+
|
277
|
+
##
|
278
|
+
# @!method tls_config_set_key_file(config, key_file)
|
279
|
+
#
|
280
|
+
# Set the private key via an absolute file path
|
281
|
+
#
|
282
|
+
# +tls_config_set_key_file+ sets the file from which the private key will
|
283
|
+
# be read.
|
284
|
+
#
|
285
|
+
# This applies to servers.
|
286
|
+
#
|
287
|
+
# @param config [FFI::Pointer] the TLS config
|
288
|
+
# @param key_file [String] absolute path to a private key in a file
|
289
|
+
# @return [Fixnum] 0 on success, -1 on error
|
290
|
+
attach_function :tls_config_set_key_file, [:pointer, :string], :int
|
291
|
+
|
292
|
+
##
|
293
|
+
# @!method tls_config_set_key_mem(config, key, len)
|
294
|
+
#
|
295
|
+
# Set the private key via a value in memory
|
296
|
+
#
|
297
|
+
# +tls_config_set_key_mem+ directly sets the private key from memory.
|
298
|
+
#
|
299
|
+
# This applies to servers.
|
300
|
+
#
|
301
|
+
# @param config [FFI::Pointer] the TLS config
|
302
|
+
# @param key [FFI::Pointer] a uint8_t pointer to the key
|
303
|
+
# @param len [Fixnum] number of bytes in the key
|
304
|
+
# @return [Fixnum] 0 on success, -1 on error
|
305
|
+
#
|
306
|
+
# @todo This is untested. Please {https://github.com/mike-burns/libtls.rb#contributing contribute a patch}.
|
307
|
+
attach_function :tls_config_set_key_mem, [:pointer, :pointer, :size_t], :int
|
308
|
+
# @!endgroup
|
309
|
+
|
310
|
+
##
|
311
|
+
# @!group Client and server configuration
|
312
|
+
# @!method tls_config_set_protocols(config, protocols)
|
313
|
+
#
|
314
|
+
# Select which protocols are to be used
|
315
|
+
#
|
316
|
+
# +tls_config_set_protocols+ sets which versions of the protocol may be
|
317
|
+
# used. Possible values are the bitwise OR of:
|
318
|
+
#
|
319
|
+
# - {TLS_PROTOCOL_TLSv1_0}
|
320
|
+
# - {TLS_PROTOCOL_TLSv1_1}
|
321
|
+
# - {TLS_PROTOCOL_TLSv1_2}
|
322
|
+
#
|
323
|
+
# Additionally, the values {TLS_PROTOCOL_TLSv1} (TLSv1.0, TLSv1.1 and
|
324
|
+
# TLSv1.2), {TLS_PROTOCOLS_ALL} (all supported protocols) and
|
325
|
+
# {TLS_PROTOCOLS_DEFAULT} (TLSv1.2 only) may be used.
|
326
|
+
#
|
327
|
+
# This applies to clients and servers.
|
328
|
+
#
|
329
|
+
# @param config [FFI::Pointer] the TLS config
|
330
|
+
# @param protocols [Fixnum] bitmask of the protocols to select
|
331
|
+
# @return [nil] +void+
|
332
|
+
attach_function :tls_config_set_protocols, [:pointer, :uint], :void
|
333
|
+
# @!endgroup
|
334
|
+
|
335
|
+
##
|
336
|
+
# @!group Client configuration
|
337
|
+
# @!method tls_config_set_verify_depth(config, verify_depth)
|
338
|
+
#
|
339
|
+
# Set the maximum depth for the certificate chain
|
340
|
+
#
|
341
|
+
# See SSL_CTX_set_verify_depth(3) for details.
|
342
|
+
#
|
343
|
+
# This applies to clients.
|
344
|
+
#
|
345
|
+
# @param config [FFI::Pointer] the TLS config
|
346
|
+
# @param verify_depth [Fixnum] the maximum depth for certificate chain
|
347
|
+
# verification
|
348
|
+
# @return [nil] +void+
|
349
|
+
#
|
350
|
+
# @todo This is untested. Please {https://github.com/mike-burns/libtls.rb#contributing contribute a patch}.
|
351
|
+
attach_function :tls_config_set_verify_depth, [:pointer, :int], :void
|
352
|
+
# @!endgroup
|
353
|
+
|
354
|
+
##
|
355
|
+
# @!group Server configuration
|
356
|
+
# @!method tls_config_clear_keys(config)
|
357
|
+
#
|
358
|
+
# Clear secret keys from memory
|
359
|
+
#
|
360
|
+
# +tls_config_clear_keys+ clears any secret keys from memory.
|
361
|
+
#
|
362
|
+
# This applies to servers.
|
363
|
+
#
|
364
|
+
# @param config [FFI::Pointer] the TLS config
|
365
|
+
# @return [nil] +void+
|
366
|
+
#
|
367
|
+
# @todo This is untested. Please {https://github.com/mike-burns/libtls.rb#contributing contribute a patch}.
|
368
|
+
attach_function :tls_config_clear_keys, [:pointer], :void
|
369
|
+
# @!endgroup
|
370
|
+
|
371
|
+
##
|
372
|
+
# @!group Client configuration
|
373
|
+
# @!method tls_config_insecure_noverifycert(config)
|
374
|
+
#
|
375
|
+
# Insecurely disable certficate verification
|
376
|
+
#
|
377
|
+
# +tls_config_insecure_noverifycert+ disables certificate verification. Be
|
378
|
+
# extremely careful when using this option.
|
379
|
+
#
|
380
|
+
# This applies to clients.
|
381
|
+
#
|
382
|
+
# @param config [FFI::Pointer] the TLS config
|
383
|
+
# @return [nil] +void+
|
384
|
+
#
|
385
|
+
# @note This method should not be used, and is therefore untested.
|
386
|
+
attach_function :tls_config_insecure_noverifycert, [:pointer], :void
|
387
|
+
|
388
|
+
##
|
389
|
+
# @!method tls_config_insecure_noverifyname(config)
|
390
|
+
#
|
391
|
+
# Insecurely disable server name verification
|
392
|
+
#
|
393
|
+
# +tls_config_insecure_noverifyname+ disables server name verification. Be
|
394
|
+
# careful when using this option.
|
395
|
+
#
|
396
|
+
# This applies to clients.
|
397
|
+
#
|
398
|
+
# @param config [FFI::Pointer] the TLS config
|
399
|
+
# @return [nil] +void+
|
400
|
+
#
|
401
|
+
# @note This method should not be used, and is therefore untested.
|
402
|
+
attach_function :tls_config_insecure_noverifyname, [:pointer], :void
|
403
|
+
|
404
|
+
##
|
405
|
+
# @!method tls_config_verify(config)
|
406
|
+
#
|
407
|
+
# Restore default verification
|
408
|
+
#
|
409
|
+
# +tls_config_verify+ reenables server name and certificate verification.
|
410
|
+
#
|
411
|
+
# This applies to clients.
|
412
|
+
#
|
413
|
+
# @param config [FFI::Pointer] the TLS config
|
414
|
+
# @return [nil] +void+
|
415
|
+
#
|
416
|
+
# @note While this method is fine, getting to this state is not. This
|
417
|
+
# method is therefore untested.
|
418
|
+
attach_function :tls_config_verify, [:pointer], :void
|
419
|
+
# @!endgroup
|
420
|
+
|
421
|
+
##
|
422
|
+
# @!group Client and server configuration
|
423
|
+
# @!method tls_load_file(file, len, password)
|
424
|
+
#
|
425
|
+
# Load a certificate or key
|
426
|
+
#
|
427
|
+
# +tls_load_file+ loads a certificate or key from disk into memory to be
|
428
|
+
# loaded with {#tls_config_set_ca_mem}, {#tls_config_set_cert_mem} or
|
429
|
+
# {#tls_config_set_key_mem}. A private key will be decrypted if the
|
430
|
+
# optional +password+ argument is specified.
|
431
|
+
#
|
432
|
+
# This applies to clients and servers.
|
433
|
+
#
|
434
|
+
# @param file [String] the absolute filename
|
435
|
+
# @param len [FFI::Pointer] pointer to a +size_t+ storing the number of
|
436
|
+
# bytes loaded
|
437
|
+
# @param password [String] either +FFI::Pointer::NULL+ or the password for
|
438
|
+
# the private key
|
439
|
+
# @return [FFI::Pointer] pointer to +uint8_t+, the key
|
440
|
+
#
|
441
|
+
# @todo This is untested. Please {https://github.com/mike-burns/libtls.rb#contributing contribute a patch}.
|
442
|
+
attach_function :tls_load_file, [:string, :pointer, :string], :pointer
|
443
|
+
# @!endgroup
|
444
|
+
|
445
|
+
##
|
446
|
+
# @!group Create, prepare, and free a connection context
|
447
|
+
# @!method tls_client()
|
448
|
+
#
|
449
|
+
# Create a client context
|
450
|
+
#
|
451
|
+
# A tls connection is represented as a context. A new context is created by
|
452
|
+
# either the {#tls_client} or {#tls_server} functions. The context can then
|
453
|
+
# be configured with the function {#tls_configure}. The same +tls_config+
|
454
|
+
# object can be used to configure multiple contexts.
|
455
|
+
#
|
456
|
+
# +tls_client+ creates a new tls context for client connections.
|
457
|
+
#
|
458
|
+
# @return [FFI::Pointer] a +tls+ context or +FFI::Pointer::NULL+ on
|
459
|
+
# failure. Check using +#null?+.
|
460
|
+
attach_function :tls_client, [], :pointer
|
461
|
+
|
462
|
+
##
|
463
|
+
# @!method tls_server()
|
464
|
+
#
|
465
|
+
# Create a server context
|
466
|
+
#
|
467
|
+
# A tls connection is represented as a context. A new context is created by
|
468
|
+
# either the {#tls_client} or {#tls_server} functions. The context can then
|
469
|
+
# be configured with the function {#tls_configure}. The same +tls_config+
|
470
|
+
# object can be used to configure multiple contexts.
|
471
|
+
#
|
472
|
+
# +tls_server+ creates a new tls context for server connections.
|
473
|
+
#
|
474
|
+
# @return [FFI::Pointer] a +tls+ context or +FFI::Pointer::NULL+ on
|
475
|
+
# failure. Check using +#null?+.
|
476
|
+
attach_function :tls_server, [], :pointer
|
477
|
+
|
478
|
+
##
|
479
|
+
# @!method tls_configure(ctx, config)
|
480
|
+
#
|
481
|
+
# Apply the configuration to the context
|
482
|
+
#
|
483
|
+
# +tls_configure+ readies a tls context for use by applying the
|
484
|
+
# configuration options.
|
485
|
+
#
|
486
|
+
# The same +tls_config+ object can be used to configure multiple contexts.
|
487
|
+
#
|
488
|
+
# @param ctx [FFI::Pointer] a TLS context
|
489
|
+
# @param config [FFI::Pointer] the TLS config
|
490
|
+
# @return [Fixnum] 0 on success, -1 on error
|
491
|
+
attach_function :tls_configure, [:pointer, :pointer], :int
|
492
|
+
|
493
|
+
##
|
494
|
+
# @!method tls_reset(ctx)
|
495
|
+
#
|
496
|
+
# Reset a context to a newly-initialized state
|
497
|
+
#
|
498
|
+
# @param ctx [FFI::Pointer] a TLS context
|
499
|
+
# @return [nil] +void+
|
500
|
+
#
|
501
|
+
# @todo This is untested. Please {https://github.com/mike-burns/libtls.rb#contributing contribute a patch}.
|
502
|
+
attach_function :tls_reset, [:pointer], :void
|
503
|
+
|
504
|
+
##
|
505
|
+
# @!method tls_close(ctx)
|
506
|
+
#
|
507
|
+
# Close the TLS connection
|
508
|
+
#
|
509
|
+
# After use, a +tls+ context should be closed with +tls_close+, and then
|
510
|
+
# freed by calling {#tls_free}. When no more contexts are to be created, the
|
511
|
+
# +tls_config+ object should be freed by calling {#tls_config_free}.
|
512
|
+
#
|
513
|
+
# +tls_close+ closes a connection after use. If the connection was
|
514
|
+
# established using +#tls_connect_fds+, only the TLS layer will be closed
|
515
|
+
# and it is the caller's responsibility to close the file descriptors.
|
516
|
+
#
|
517
|
+
# @param ctx [FFI::Pointer] a TLS context
|
518
|
+
# @return [Fixnum] 0 on success, -1 on error, {TLS_READ_AGAIN} if a read
|
519
|
+
# opreation is necessary to continue, {TLS_WRITE_AGAIN} if a write
|
520
|
+
# operation is necessary to continue. In case of a {TLS_READ_AGAIN} or
|
521
|
+
# {TLS_WRITE_AGAIN}, the caller should repeat the call.
|
522
|
+
attach_function :tls_close, [:pointer], :int
|
523
|
+
|
524
|
+
##
|
525
|
+
# @!method tls_free(ctx)
|
526
|
+
#
|
527
|
+
# Free memory for the TLS context
|
528
|
+
#
|
529
|
+
# After use, a +tls+ context should be closed with +tls_close+, and then
|
530
|
+
# freed by calling {#tls_free}. When no more contexts are to be created, the
|
531
|
+
# +tls_config+ object should be freed by calling {#tls_config_free}.
|
532
|
+
#
|
533
|
+
# +tls_free+ frees a tls context after use.
|
534
|
+
#
|
535
|
+
# @param ctx [FFI::Pointer] a TLS context
|
536
|
+
attach_function :tls_free, [:pointer], :void
|
537
|
+
# @!endgroup
|
538
|
+
|
539
|
+
##
|
540
|
+
# @!group Initiate a connection and perform I/O
|
541
|
+
# @!method tls_connect(ctx, host, port)
|
542
|
+
#
|
543
|
+
# Open a TLS connection to the +host+ and +port+
|
544
|
+
#
|
545
|
+
# A client connection is initiated after configuration by calling
|
546
|
+
# +tls_connect+. This function will create a new socket, connect to the
|
547
|
+
# specified host and port, and then establish a secure connection.
|
548
|
+
#
|
549
|
+
# +tls_connect+ connects a client context to the server named by host. The
|
550
|
+
# port may be numeric or a service name. If it is +FFI::Pointer::NULL+ then
|
551
|
+
# a host of the format "hostname:port" is permitted.
|
552
|
+
#
|
553
|
+
# @param ctx [FFI::Pointer] a TLS context
|
554
|
+
# @param host [String] the server to connect to, as an IPv4 address, an
|
555
|
+
# IPv6 address, anything that can be resolved by +getaddrinfo+.
|
556
|
+
# @param port [String] the port as a number, service name, or NULL pointer.
|
557
|
+
# If it is a NULL pointer, the host is parsed for the port number.
|
558
|
+
# @return [Fixnum] 0 on success, -1 on error, {TLS_READ_AGAIN} if a read
|
559
|
+
# opreation is necessary to continue, {TLS_WRITE_AGAIN} if a write
|
560
|
+
# operation is necessary to continue. In case of a {TLS_READ_AGAIN} or
|
561
|
+
# {TLS_WRITE_AGAIN}, the caller should repeat the call.
|
562
|
+
attach_function :tls_connect, [:pointer, :string, :string], :int
|
563
|
+
|
564
|
+
##
|
565
|
+
# @!method tls_connect_fds(ctx, fd_read, fd_write, servername)
|
566
|
+
#
|
567
|
+
# Upgrade an existing connection to secure
|
568
|
+
#
|
569
|
+
# +tls_connect_fds+ connects a client context to a pair of existing file
|
570
|
+
# descriptors.
|
571
|
+
#
|
572
|
+
# @param ctx [FFI::Pointer] a TLS context
|
573
|
+
# @param fd_read [Fixnum] the read file descriptor
|
574
|
+
# @param fd_write [Fixnum] the write file descriptor
|
575
|
+
# @param servername [String] the name of the server, as matched in the
|
576
|
+
# certificate
|
577
|
+
# @return [Fixnum] 0 on success, -1 on error, {TLS_READ_AGAIN} if a read
|
578
|
+
# opreation is necessary to continue, {TLS_WRITE_AGAIN} if a write
|
579
|
+
# operation is necessary to continue. In case of a {TLS_READ_AGAIN} or
|
580
|
+
# {TLS_WRITE_AGAIN}, the caller should repeat the call.
|
581
|
+
#
|
582
|
+
# @todo This is untested. Please {https://github.com/mike-burns/libtls.rb#contributing contribute a patch}.
|
583
|
+
attach_function :tls_connect_fds, [:pointer, :int, :int, :string], :int
|
584
|
+
|
585
|
+
##
|
586
|
+
# @!method tls_connect_servername(ctx, host, port, servername)
|
587
|
+
#
|
588
|
+
# Open a TLS connection to the +host+ and +port+, verifying against
|
589
|
+
# +servername+
|
590
|
+
#
|
591
|
+
# The +tls_connect_servername+ function has the same behaviour as
|
592
|
+
# {#tls_connect}, however the name to use for verification is explicitly
|
593
|
+
# provided, rather than being inferred from the host value.
|
594
|
+
#
|
595
|
+
# @param ctx [FFI::Pointer] a TLS context
|
596
|
+
# @param host [String] the server to connect to, as an IPv4 address, an
|
597
|
+
# IPv6 address, anything that can be resolved by +getaddrinfo+.
|
598
|
+
# @param port [String] the port as a number, service name, or NULL pointer.
|
599
|
+
# If it is a NULL pointer, the host is parsed for the port number.
|
600
|
+
# @param servername [String] the server name to verify the certificate
|
601
|
+
# against
|
602
|
+
# @return [Fixnum] 0 on success, -1 on error, {TLS_READ_AGAIN} if a read
|
603
|
+
# opreation is necessary to continue, {TLS_WRITE_AGAIN} if a write
|
604
|
+
# operation is necessary to continue. In case of a {TLS_READ_AGAIN} or
|
605
|
+
# {TLS_WRITE_AGAIN}, the caller should repeat the call.
|
606
|
+
#
|
607
|
+
# @todo This is untested. Please {https://github.com/mike-burns/libtls.rb#contributing contribute a patch}.
|
608
|
+
attach_function :tls_connect_servername,
|
609
|
+
[:pointer, :string, :string, :string], :int
|
610
|
+
|
611
|
+
##
|
612
|
+
# @!method tls_connect_socket(ctx, s, servername)
|
613
|
+
#
|
614
|
+
# Upgrade an existing socket
|
615
|
+
#
|
616
|
+
# +tls_connect_socket+ connects a client context to an already established
|
617
|
+
# socket connection.
|
618
|
+
#
|
619
|
+
# @param ctx [FFI::Pointer] a TLS context
|
620
|
+
# @param s [Fixnum] the file descriptor for a socket
|
621
|
+
# @param servername [String] the server name to verify the certificate
|
622
|
+
# against
|
623
|
+
# @return [Fixnum] 0 on success, -1 on error, {TLS_READ_AGAIN} if a read
|
624
|
+
# opreation is necessary to continue, {TLS_WRITE_AGAIN} if a write
|
625
|
+
# operation is necessary to continue. In case of a {TLS_READ_AGAIN} or
|
626
|
+
# {TLS_WRITE_AGAIN}, the caller should repeat the call.
|
627
|
+
#
|
628
|
+
# @todo This is untested. Please {https://github.com/mike-burns/libtls.rb#contributing contribute a patch}.
|
629
|
+
attach_function :tls_connect_socket, [:pointer, :int, :string], :int
|
630
|
+
|
631
|
+
##
|
632
|
+
# @!method tls_accept_fds(ctx, cctx, fd_read, fd_write)
|
633
|
+
#
|
634
|
+
# Perform the TLS handshake on an established pair of file descriptors
|
635
|
+
#
|
636
|
+
# +tls_accept_fds+ creates a new context suitable for reading and writing
|
637
|
+
# on an existing pair of file descriptors and returns it in +*cctx+. A
|
638
|
+
# configured server context should be passed in +ctx+ and +*cctx+ should be
|
639
|
+
# initialized to NULL.
|
640
|
+
#
|
641
|
+
# @see #tls_accept_socket
|
642
|
+
#
|
643
|
+
# @param ctx [FFI::Pointer] a TLS context
|
644
|
+
# @param cctx [FFI::Pointer] a reference to a TLS context
|
645
|
+
# @param fd_read [Fixnum] the read file descriptor
|
646
|
+
# @param fd_write [Fixnum] the write file descriptor
|
647
|
+
# @return [Fixnum] 0 on success, -1 on error, {TLS_READ_AGAIN} if a read
|
648
|
+
# opreation is necessary to continue, {TLS_WRITE_AGAIN} if a write
|
649
|
+
# operation is necessary to continue. In case of a {TLS_READ_AGAIN} or
|
650
|
+
# {TLS_WRITE_AGAIN}, the caller should repeat the call.
|
651
|
+
#
|
652
|
+
# @todo This is untested. Please {https://github.com/mike-burns/libtls.rb#contributing contribute a patch}.
|
653
|
+
attach_function :tls_accept_fds, [:pointer, :pointer, :int, :int], :int
|
654
|
+
|
655
|
+
##
|
656
|
+
# @!method tls_accept_socket(ctx, cctx, socket)
|
657
|
+
#
|
658
|
+
# Perform the TLS handshake on an established socket
|
659
|
+
#
|
660
|
+
# A server can accept a new client connection by calling
|
661
|
+
# +tls_accept_socket+ on an already established socket connection.
|
662
|
+
#
|
663
|
+
# +tls_accept_socket+ creates a new context suitable for reading and
|
664
|
+
# writing on an already established socket connection and returns it in
|
665
|
+
# +*cctx+. A configured server context should be passed in +ctx+ and
|
666
|
+
# +*cctx+ should be initialized to +NULL+.
|
667
|
+
#
|
668
|
+
# The pattern looks like this:
|
669
|
+
#
|
670
|
+
# cctx_ptr = FFI::MemoryPointer.new(:pointer)
|
671
|
+
# LibTLS::Raw.tls_accept_socket(ctx, cctx_ptr, client_sock.fileno)
|
672
|
+
# cctx = cctx_ptr.read_pointer
|
673
|
+
#
|
674
|
+
# @param ctx [FFI::Pointer] a TLS context
|
675
|
+
# @param cctx [FFI::Pointer] a reference to a TLS context
|
676
|
+
# @param socket [Int] the file descriptor of an established socket that is
|
677
|
+
# connected to a client. Use +Socket#fileno+ to get the file descriptor
|
678
|
+
# of a Socket instance.
|
679
|
+
# @return [Fixnum] 0 on success, -1 on error, {TLS_READ_AGAIN} if a read
|
680
|
+
# opreation is necessary to continue, {TLS_WRITE_AGAIN} if a write
|
681
|
+
# operation is necessary to continue. In case of a {TLS_READ_AGAIN} or
|
682
|
+
# {TLS_WRITE_AGAIN}, the caller should repeat the call.
|
683
|
+
attach_function :tls_accept_socket, [:pointer, :pointer, :int], :int
|
684
|
+
|
685
|
+
##
|
686
|
+
# @!method tls_read(ctx, buf, buflen, outlen)
|
687
|
+
#
|
688
|
+
# Read from the socket
|
689
|
+
#
|
690
|
+
# +tls_read+ reads +buflen+ bytes of data from the socket into +buf+. The
|
691
|
+
# amount of data read is returned in +outlen+.
|
692
|
+
#
|
693
|
+
# The pattern is as follows:
|
694
|
+
#
|
695
|
+
#
|
696
|
+
# READ_LEN = 1024
|
697
|
+
# FFI::MemoryPointer.new(:size_t) do |outlen|
|
698
|
+
# FFI::MemoryPointer.new(:uchar, READ_LEN, true) do |buf|
|
699
|
+
# loop do
|
700
|
+
# if LibTLS::Raw.tls_read(ctx, buf, READ_LEN, outlen) < 0
|
701
|
+
# raise LibTLS::CError, "tls_read: #{LibTLS::Raw.tls_error(ctx)}"
|
702
|
+
# end
|
703
|
+
#
|
704
|
+
# do_something_with( buf.get_string(0, outlen.get_int(0)) )
|
705
|
+
#
|
706
|
+
# if READ_LEN > outlen.get_int(0)
|
707
|
+
# break
|
708
|
+
# end
|
709
|
+
# end
|
710
|
+
# end
|
711
|
+
# end
|
712
|
+
#
|
713
|
+
# @param ctx [FFI::Pointer] a TLS context
|
714
|
+
# @param buf [FFI::Pointer] allocated memory for a +buflen+ number of
|
715
|
+
# +uchars+
|
716
|
+
# @param buflen [Fixnum] the number of bytes to read
|
717
|
+
# @param outlen [FFI::Pointer] the number of bytes read
|
718
|
+
# @return [Fixnum] 0 on success, -1 on error, {TLS_READ_AGAIN} if a read
|
719
|
+
# opreation is necessary to continue, {TLS_WRITE_AGAIN} if a write
|
720
|
+
# operation is necessary to continue. In the case of a {TLS_READ_AGAIN} the
|
721
|
+
# caller should repeat the call. In the case of a {TLS_WRITE_AGAIN}, the
|
722
|
+
# caller should call {#tls_write}.
|
723
|
+
attach_function :tls_read, [:pointer, :pointer, :size_t, :pointer], :int
|
724
|
+
|
725
|
+
##
|
726
|
+
# @!method tls_write(ctx, buf, buflen, outlen)
|
727
|
+
#
|
728
|
+
# Write data to the socket
|
729
|
+
#
|
730
|
+
# +tls_write+ writes +buflen+ bytes of data from +buf+ to the socket. The
|
731
|
+
# amount of data written is returned in +outlen+.
|
732
|
+
#
|
733
|
+
# The pattern is as follows:
|
734
|
+
#
|
735
|
+
# STR = "HELLO\r\n"
|
736
|
+
#
|
737
|
+
# FFI::MemoryPointer.new(:size_t) do |outlen|
|
738
|
+
# FFI::MemoryPointer.new(:uchar, STR.length + 1) do |str_ptr|
|
739
|
+
# str_ptr.put_string(0, STR)
|
740
|
+
#
|
741
|
+
# if LibTLS::Raw.tls_write(ctx, str_ptr, STR.length, outlen) < 0
|
742
|
+
# raise LibTLS::CError, "tls_write: #{LibTLS::Raw.tls_error(ctx)}"
|
743
|
+
# end
|
744
|
+
# end
|
745
|
+
# end
|
746
|
+
#
|
747
|
+
# @param ctx [FFI::Pointer] a TLS context
|
748
|
+
# @param buf [FFI::Pointer] a pointer to the string of +uchar+s
|
749
|
+
# @param buflen [Fixnum] the number of bytes to write
|
750
|
+
# @param outlen [FFI::Pointer] the number of bytes written
|
751
|
+
# @return [Fixnum] 0 on success, -1 on error, {TLS_READ_AGAIN} if a read
|
752
|
+
# opreation is necessary to continue, {TLS_WRITE_AGAIN} if a write
|
753
|
+
# operation is necessary to continue. In the case of a {TLS_READ_AGAIN} the
|
754
|
+
# caller should call {#tls_read}. In the case of a {TLS_WRITE_AGAIN}, the
|
755
|
+
# caller should repeat the call.
|
756
|
+
attach_function :tls_write, [:pointer, :pointer, :size_t, :pointer], :int
|
757
|
+
# @!endgroup
|
758
|
+
end
|
759
|
+
end
|