iodine 0.7.60 → 0.8.0

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.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/.clang-format +15 -0
  3. data/.rspec +1 -0
  4. data/.yardopts +1 -3
  5. data/CHANGELOG.md +132 -12
  6. data/Gemfile +5 -7
  7. data/LICENSE.txt +1 -1
  8. data/README.md +147 -671
  9. data/Rakefile +9 -16
  10. data/examples/chatroom.nru +9 -0
  11. data/examples/client +74 -0
  12. data/examples/config-hello.nru +9 -0
  13. data/examples/config-hello.ru +11 -0
  14. data/examples/config-hijack.ru +13 -0
  15. data/examples/config-shootout.ru +43 -0
  16. data/examples/config.nru +120 -0
  17. data/examples/config.rb +37 -0
  18. data/examples/config.ru +42 -53
  19. data/examples/fake +24 -0
  20. data/examples/hello_neorack +137 -0
  21. data/examples/routes.nru +29 -0
  22. data/examples/routes.ru +42 -0
  23. data/exe/iodine +218 -258
  24. data/ext/iodine/extconf.rb +27 -100
  25. data/ext/iodine/fio-stl.h +128336 -0
  26. data/ext/iodine/fio-stl.md +26396 -0
  27. data/ext/iodine/iodine.c +213 -1393
  28. data/ext/iodine/iodine.h +250 -55
  29. data/ext/iodine/iodine_arg_helper.h +329 -0
  30. data/ext/iodine/iodine_caller.h +234 -25
  31. data/ext/iodine/iodine_cli.h +434 -0
  32. data/ext/iodine/iodine_compression.h +312 -0
  33. data/ext/iodine/iodine_connection.h +3484 -34
  34. data/ext/iodine/iodine_core.h +363 -0
  35. data/ext/iodine/iodine_crypto.h +1441 -0
  36. data/ext/iodine/iodine_defer.h +225 -4
  37. data/ext/iodine/iodine_json.h +738 -4
  38. data/ext/iodine/iodine_listener.h +263 -0
  39. data/ext/iodine/iodine_log.h +297 -0
  40. data/ext/iodine/iodine_minimap.h +543 -0
  41. data/ext/iodine/iodine_mustache.h +461 -4
  42. data/ext/iodine/iodine_pubsub_eng.h +729 -0
  43. data/ext/iodine/iodine_pubsub_history.h +547 -0
  44. data/ext/iodine/iodine_pubsub_msg.h +228 -0
  45. data/ext/iodine/iodine_redis.h +322 -0
  46. data/ext/iodine/iodine_store.h +418 -16
  47. data/ext/iodine/iodine_threads.h +279 -0
  48. data/ext/iodine/iodine_tls.h +515 -6
  49. data/ext/iodine/iodine_utils.h +923 -0
  50. data/iodine.gemspec +37 -42
  51. data/lib/iodine/benchmark.rb +1690 -0
  52. data/lib/iodine/documentation.rb +3085 -0
  53. data/lib/iodine/version.rb +17 -1
  54. data/lib/iodine.rb +54 -255
  55. data/logo.svg +36 -0
  56. data/mustache.md +55 -0
  57. data/sig/iodine.rbs +4 -0
  58. metadata +58 -184
  59. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
  60. data/.github/workflows/ruby.yml +0 -42
  61. data/.gitignore +0 -21
  62. data/LIMITS.md +0 -41
  63. data/SPEC-PubSub-Draft.md +0 -159
  64. data/SPEC-WebSocket-Draft.md +0 -239
  65. data/bin/console +0 -22
  66. data/bin/info.md +0 -353
  67. data/bin/mustache_bench.rb +0 -100
  68. data/bin/poc/Gemfile.lock +0 -23
  69. data/bin/poc/README.md +0 -37
  70. data/bin/poc/config.ru +0 -66
  71. data/bin/poc/gemfile +0 -1
  72. data/bin/poc/www/index.html +0 -57
  73. data/examples/async_task.ru +0 -92
  74. data/examples/bates/README.md +0 -3
  75. data/examples/bates/config.ru +0 -342
  76. data/examples/bates/david+bold.pdf +0 -0
  77. data/examples/bates/public/drop-pdf.png +0 -0
  78. data/examples/bates/public/index.html +0 -600
  79. data/examples/echo.ru +0 -59
  80. data/examples/etag.ru +0 -16
  81. data/examples/hello.ru +0 -29
  82. data/examples/pubsub_engine.ru +0 -81
  83. data/examples/rack3.ru +0 -12
  84. data/examples/redis.ru +0 -70
  85. data/examples/shootout.ru +0 -73
  86. data/examples/sub-protocols.ru +0 -90
  87. data/examples/tcp_client.rb +0 -66
  88. data/examples/x-sendfile.ru +0 -14
  89. data/ext/iodine/fio.c +0 -11995
  90. data/ext/iodine/fio.h +0 -6371
  91. data/ext/iodine/fio_cli.c +0 -431
  92. data/ext/iodine/fio_cli.h +0 -189
  93. data/ext/iodine/fio_json_parser.h +0 -688
  94. data/ext/iodine/fio_siphash.c +0 -157
  95. data/ext/iodine/fio_siphash.h +0 -37
  96. data/ext/iodine/fio_tls.h +0 -129
  97. data/ext/iodine/fio_tls_missing.c +0 -649
  98. data/ext/iodine/fio_tls_openssl.c +0 -1106
  99. data/ext/iodine/fio_tmpfile.h +0 -50
  100. data/ext/iodine/fiobj.h +0 -44
  101. data/ext/iodine/fiobj4fio.h +0 -21
  102. data/ext/iodine/fiobj_ary.c +0 -333
  103. data/ext/iodine/fiobj_ary.h +0 -139
  104. data/ext/iodine/fiobj_data.c +0 -1187
  105. data/ext/iodine/fiobj_data.h +0 -167
  106. data/ext/iodine/fiobj_hash.c +0 -409
  107. data/ext/iodine/fiobj_hash.h +0 -176
  108. data/ext/iodine/fiobj_json.c +0 -622
  109. data/ext/iodine/fiobj_json.h +0 -68
  110. data/ext/iodine/fiobj_mem.h +0 -71
  111. data/ext/iodine/fiobj_mustache.c +0 -317
  112. data/ext/iodine/fiobj_mustache.h +0 -62
  113. data/ext/iodine/fiobj_numbers.c +0 -344
  114. data/ext/iodine/fiobj_numbers.h +0 -127
  115. data/ext/iodine/fiobj_str.c +0 -433
  116. data/ext/iodine/fiobj_str.h +0 -172
  117. data/ext/iodine/fiobject.c +0 -620
  118. data/ext/iodine/fiobject.h +0 -655
  119. data/ext/iodine/hpack.h +0 -1923
  120. data/ext/iodine/http.c +0 -2743
  121. data/ext/iodine/http.h +0 -1002
  122. data/ext/iodine/http1.c +0 -910
  123. data/ext/iodine/http1.h +0 -29
  124. data/ext/iodine/http1_parser.h +0 -878
  125. data/ext/iodine/http_internal.c +0 -1279
  126. data/ext/iodine/http_internal.h +0 -237
  127. data/ext/iodine/http_mime_parser.h +0 -350
  128. data/ext/iodine/iodine_caller.c +0 -230
  129. data/ext/iodine/iodine_connection.c +0 -941
  130. data/ext/iodine/iodine_defer.c +0 -420
  131. data/ext/iodine/iodine_fiobj2rb.h +0 -120
  132. data/ext/iodine/iodine_helpers.c +0 -282
  133. data/ext/iodine/iodine_helpers.h +0 -12
  134. data/ext/iodine/iodine_http.c +0 -1181
  135. data/ext/iodine/iodine_http.h +0 -23
  136. data/ext/iodine/iodine_json.c +0 -302
  137. data/ext/iodine/iodine_mustache.c +0 -567
  138. data/ext/iodine/iodine_pubsub.c +0 -580
  139. data/ext/iodine/iodine_pubsub.h +0 -26
  140. data/ext/iodine/iodine_rack_io.c +0 -273
  141. data/ext/iodine/iodine_rack_io.h +0 -20
  142. data/ext/iodine/iodine_store.c +0 -148
  143. data/ext/iodine/iodine_tcp.c +0 -346
  144. data/ext/iodine/iodine_tcp.h +0 -13
  145. data/ext/iodine/iodine_tls.c +0 -261
  146. data/ext/iodine/mustache_parser.h +0 -1546
  147. data/ext/iodine/redis_engine.c +0 -957
  148. data/ext/iodine/redis_engine.h +0 -79
  149. data/ext/iodine/resp_parser.h +0 -317
  150. data/ext/iodine/websocket_parser.h +0 -506
  151. data/ext/iodine/websockets.c +0 -743
  152. data/ext/iodine/websockets.h +0 -185
  153. data/lib/iodine/connection.rb +0 -61
  154. data/lib/iodine/json.rb +0 -42
  155. data/lib/iodine/mustache.rb +0 -113
  156. data/lib/iodine/pubsub.rb +0 -55
  157. data/lib/iodine/rack_utils.rb +0 -43
  158. data/lib/iodine/tls.rb +0 -16
  159. data/lib/rack/handler/iodine.rb +0 -33
  160. data/logo.png +0 -0
@@ -1,1106 +0,0 @@
1
- /*
2
- Copyright: Boaz Segev, 2018-2019
3
- License: MIT
4
-
5
- Feel free to copy, use and enjoy according to the license provided.
6
- */
7
- #ifdef __MINGW32__
8
- // make pedantic compiler happy
9
- typedef struct {
10
- int bogus;
11
- } bogus_s;
12
-
13
- #else
14
- #include <fio.h>
15
-
16
- /**
17
- * This implementation of the facil.io SSL/TLS wrapper API wraps the OpenSSL API
18
- * to provide TLS 1.2 and TLS 1.3 to facil.io applications.
19
- *
20
- * The implementation requires `HAVE_OPENSSL` to be set.
21
- */
22
- #include "fio_tls.h"
23
-
24
- #if HAVE_OPENSSL
25
- #include <openssl/bio.h>
26
- #include <openssl/err.h>
27
- #include <openssl/ssl.h>
28
-
29
- #define REQUIRE_LIBRARY()
30
- #define FIO_TLS_WEAK
31
-
32
- /* *****************************************************************************
33
- The SSL/TLS helper data types (can be left as is)
34
- ***************************************************************************** */
35
- #define FIO_INCLUDE_STR 1
36
- #define FIO_FORCE_MALLOC_TMP 1
37
- #include <fio.h>
38
-
39
- #ifndef FIO_TLS_TIMEOUT
40
- #define FIO_TLS_TIMEOUT 4
41
- #endif
42
-
43
- typedef struct {
44
- fio_str_s private_key;
45
- fio_str_s public_key;
46
- fio_str_s password;
47
- } cert_s;
48
-
49
- static inline int fio_tls_cert_cmp(const cert_s *dest, const cert_s *src) {
50
- return fio_str_iseq(&dest->private_key, &src->private_key);
51
- }
52
- static inline void fio_tls_cert_copy(cert_s *dest, cert_s *src) {
53
- *dest = (cert_s){
54
- .private_key = FIO_STR_INIT,
55
- .public_key = FIO_STR_INIT,
56
- .password = FIO_STR_INIT,
57
- };
58
- fio_str_concat(&dest->private_key, &src->private_key);
59
- fio_str_concat(&dest->public_key, &src->public_key);
60
- fio_str_concat(&dest->password, &src->password);
61
- }
62
- static inline void fio_tls_cert_destroy(cert_s *obj) {
63
- fio_str_free(&obj->private_key);
64
- fio_str_free(&obj->public_key);
65
- fio_str_free(&obj->password);
66
- }
67
-
68
- #define FIO_ARY_NAME cert_ary
69
- #define FIO_ARY_TYPE cert_s
70
- #define FIO_ARY_COMPARE(k1, k2) (fio_tls_cert_cmp(&(k1), &(k2)))
71
- #define FIO_ARY_COPY(dest, obj) fio_tls_cert_copy(&(dest), &(obj))
72
- #define FIO_ARY_DESTROY(key) fio_tls_cert_destroy(&(key))
73
- #define FIO_FORCE_MALLOC_TMP 1
74
- #include <fio.h>
75
-
76
- typedef struct {
77
- fio_str_s pem;
78
- } trust_s;
79
-
80
- static inline int fio_tls_trust_cmp(const trust_s *dest, const trust_s *src) {
81
- return fio_str_iseq(&dest->pem, &src->pem);
82
- }
83
- static inline void fio_tls_trust_copy(trust_s *dest, trust_s *src) {
84
- *dest = (trust_s){
85
- .pem = FIO_STR_INIT,
86
- };
87
- fio_str_concat(&dest->pem, &src->pem);
88
- }
89
- static inline void fio_tls_trust_destroy(trust_s *obj) {
90
- fio_str_free(&obj->pem);
91
- }
92
-
93
- #define FIO_ARY_NAME trust_ary
94
- #define FIO_ARY_TYPE trust_s
95
- #define FIO_ARY_COMPARE(k1, k2) (fio_tls_trust_cmp(&(k1), &(k2)))
96
- #define FIO_ARY_COPY(dest, obj) fio_tls_trust_copy(&(dest), &(obj))
97
- #define FIO_ARY_DESTROY(key) fio_tls_trust_destroy(&(key))
98
- #define FIO_FORCE_MALLOC_TMP 1
99
- #include <fio.h>
100
-
101
- typedef struct {
102
- fio_str_s name; /* fio_str_s provides cache locality for small strings */
103
- void (*on_selected)(intptr_t uuid, void *udata_connection, void *udata_tls);
104
- void *udata_tls;
105
- void (*on_cleanup)(void *udata_tls);
106
- } alpn_s;
107
-
108
- static inline int fio_alpn_cmp(const alpn_s *dest, const alpn_s *src) {
109
- return fio_str_iseq(&dest->name, &src->name);
110
- }
111
- static inline void fio_alpn_copy(alpn_s *dest, alpn_s *src) {
112
- *dest = (alpn_s){
113
- .name = FIO_STR_INIT,
114
- .on_selected = src->on_selected,
115
- .udata_tls = src->udata_tls,
116
- .on_cleanup = src->on_cleanup,
117
- };
118
- fio_str_concat(&dest->name, &src->name);
119
- }
120
- static inline void fio_alpn_destroy(alpn_s *obj) {
121
- if (obj->on_cleanup)
122
- obj->on_cleanup(obj->udata_tls);
123
- fio_str_free(&obj->name);
124
- }
125
-
126
- #define FIO_SET_NAME alpn_list
127
- #define FIO_SET_OBJ_TYPE alpn_s
128
- #define FIO_SET_OBJ_COMPARE(k1, k2) fio_alpn_cmp(&(k1), &(k2))
129
- #define FIO_SET_OBJ_COPY(dest, obj) fio_alpn_copy(&(dest), &(obj))
130
- #define FIO_SET_OBJ_DESTROY(key) fio_alpn_destroy(&(key))
131
- #define FIO_FORCE_MALLOC_TMP 1
132
- #include <fio.h>
133
-
134
- /* *****************************************************************************
135
- The SSL/TLS type
136
- ***************************************************************************** */
137
-
138
- /** An opaque type used for the SSL/TLS functions. */
139
- struct fio_tls_s {
140
- size_t ref; /* Reference counter, to guards the ALPN registry */
141
- alpn_list_s alpn; /* ALPN is the name for the protocol selection extension */
142
-
143
- /*** the next two components could be optimized away with tweaking stuff ***/
144
-
145
- cert_ary_s sni; /* SNI (server name extension) stores ID certificates */
146
- trust_ary_s trust; /* Trusted certificate registry (peer verification) */
147
-
148
- /************ TODO: implementation data fields go here ******************/
149
-
150
- SSL_CTX *ctx; /* The Open SSL context (updated each time). */
151
- unsigned char *alpn_str; /* the computed server-format ALPN string */
152
- int alpn_len;
153
- };
154
-
155
- /* *****************************************************************************
156
- ALPN Helpers
157
- ***************************************************************************** */
158
-
159
- /** Returns a pointer to the ALPN data (callback, etc') IF exists in the TLS. */
160
- FIO_FUNC inline alpn_s *alpn_find(fio_tls_s *tls, char *name, size_t len) {
161
- alpn_s tmp = {.name = FIO_STR_INIT_STATIC2(name, len)};
162
- alpn_list__map_s_ *pos =
163
- alpn_list__find_map_pos_(&tls->alpn, fio_str_hash(&tmp.name), tmp);
164
- if (!pos || !pos->pos)
165
- return NULL;
166
- return &pos->pos->obj;
167
- }
168
-
169
- /** Adds an ALPN data object to the ALPN "list" (set) */
170
- FIO_FUNC inline void alpn_add(fio_tls_s *tls,
171
- const char *protocol_name,
172
- void (*on_selected)(intptr_t uuid,
173
- void *udata_connection,
174
- void *udata_tls),
175
- void *udata_tls,
176
- void (*on_cleanup)(void *udata_tls)) {
177
- alpn_s tmp = {
178
- .name = FIO_STR_INIT_STATIC(protocol_name),
179
- .on_selected = on_selected,
180
- .udata_tls = udata_tls,
181
- .on_cleanup = on_cleanup,
182
- };
183
- if (fio_str_len(&tmp.name) > 255) {
184
- FIO_LOG_ERROR("ALPN protocol names are limited to 255 bytes.");
185
- return;
186
- }
187
- alpn_list_overwrite(&tls->alpn, fio_str_hash(&tmp.name), tmp, NULL);
188
- tmp.on_cleanup = NULL;
189
- fio_alpn_destroy(&tmp);
190
- }
191
-
192
- /** Returns a pointer to the default (first) ALPN object in the TLS (if any). */
193
- FIO_FUNC inline alpn_s *alpn_default(fio_tls_s *tls) {
194
- if (!tls || !alpn_list_count(&tls->alpn) || !tls->alpn.ordered)
195
- return NULL;
196
- return &tls->alpn.ordered[0].obj;
197
- }
198
-
199
- typedef struct {
200
- alpn_s alpn;
201
- intptr_t uuid;
202
- void *udata_connection;
203
- } alpn_task_s;
204
-
205
- FIO_FUNC inline void alpn_select___task(void *t_, void *ignr_) {
206
- alpn_task_s *t = t_;
207
- if (fio_is_valid(t->uuid)) {
208
- fio_timeout_set(t->uuid, 0); // remove TLS timeout
209
- t->alpn.on_selected(t->uuid, t->udata_connection, t->alpn.udata_tls);
210
- } else {
211
- t->alpn.on_selected(-1, t->udata_connection, t->alpn.udata_tls);
212
- }
213
- fio_free(t);
214
- (void)ignr_;
215
- }
216
-
217
- /** Schedules the ALPN protocol callback. */
218
- FIO_FUNC inline void alpn_select(alpn_s *alpn,
219
- intptr_t uuid,
220
- void *udata_connection) {
221
- if (!alpn || !alpn->on_selected)
222
- return;
223
- alpn_task_s *t = fio_malloc(sizeof(*t));
224
- *t = (alpn_task_s){
225
- .alpn = *alpn,
226
- .uuid = uuid,
227
- .udata_connection = udata_connection,
228
- };
229
- fio_defer(alpn_select___task, t, NULL);
230
- }
231
-
232
- /* *****************************************************************************
233
- OpenSSL Helpers
234
- ***************************************************************************** */
235
-
236
- static EVP_PKEY *fio_tls_pkey = NULL;
237
-
238
- static void fio_tls_clear_root_key(void *key) {
239
- EVP_PKEY_free(key);
240
- fio_tls_pkey = NULL;
241
- }
242
-
243
- static void fio_tls_make_root_key(void) {
244
- static fio_lock_i lock = FIO_LOCK_INIT;
245
- fio_lock(&lock);
246
- if (fio_tls_pkey)
247
- goto finish;
248
- /* create private key, free it at exit */
249
- FIO_LOG_DEBUG("calculating a new TLS private key... might take a while.");
250
-
251
- fio_tls_pkey = EVP_PKEY_new();
252
- FIO_ASSERT(fio_tls_pkey, "OpenSSL failed to create private key.");
253
-
254
- /* TODO: replace RSA with something else? is there something else? */
255
- RSA *rsa = RSA_new();
256
- BIGNUM *e = BN_new();
257
- BN_clear(e);
258
- BN_add_word(e, 65537);
259
- FIO_ASSERT_ALLOC(e);
260
- FIO_ASSERT(RSA_generate_key_ex(rsa, 2048, e, NULL),
261
- "OpenSSL failed to create RSA key.");
262
- BN_free(e);
263
- EVP_PKEY_assign_RSA(fio_tls_pkey, rsa);
264
- fio_state_callback_add(FIO_CALL_AT_EXIT,
265
- fio_tls_clear_root_key,
266
- fio_tls_pkey);
267
- finish:
268
- fio_unlock(&lock);
269
- }
270
-
271
- static X509 *fio_tls_create_self_signed(char *server_name) {
272
- X509 *cert = X509_new();
273
- static uint32_t counter = 0;
274
- FIO_ASSERT(cert,
275
- "OpenSSL failed to allocate memory for self-signed ceritifcate.");
276
- fio_tls_make_root_key();
277
-
278
- /* serial number */
279
- fio_atomic_add(&counter, 1);
280
- ASN1_INTEGER_set(X509_get_serialNumber(cert), counter);
281
-
282
- /* validity (180 days) */
283
- X509_gmtime_adj(X509_get_notBefore(cert), 0);
284
- X509_gmtime_adj(X509_get_notAfter(cert), 15552000L);
285
-
286
- /* set (public) key */
287
- X509_set_pubkey(cert, fio_tls_pkey);
288
-
289
- /* set identity details */
290
- X509_NAME *s = X509_get_subject_name(cert);
291
- size_t srv_name_len = strlen(server_name);
292
- X509_NAME_add_entry_by_txt(s,
293
- "O",
294
- MBSTRING_ASC,
295
- (unsigned char *)server_name,
296
- srv_name_len,
297
- -1,
298
- 0);
299
- X509_NAME_add_entry_by_txt(s,
300
- "CN",
301
- MBSTRING_ASC,
302
- (unsigned char *)server_name,
303
- srv_name_len,
304
- -1,
305
- 0);
306
- X509_NAME_add_entry_by_txt(s,
307
- "CA",
308
- MBSTRING_ASC,
309
- (unsigned char *)server_name,
310
- srv_name_len,
311
- -1,
312
- 0);
313
- X509_set_issuer_name(cert, s);
314
-
315
- /* sign certificate */
316
- FIO_ASSERT(X509_sign(cert, fio_tls_pkey, EVP_sha512()),
317
- "OpenSSL failed to signe self-signed certificate");
318
- // FILE *fp = fopen("tmp.pem", "ab+");
319
- // if (fp) {
320
- // PEM_write_X509(fp, cert);
321
- // fclose(fp);
322
- // }
323
-
324
- return cert;
325
- }
326
-
327
- /* *****************************************************************************
328
- SSL/TLS Context (re)-building
329
- ***************************************************************************** */
330
-
331
- #define TLS_BUFFER_LENGTH (1 << 15)
332
- typedef struct {
333
- SSL *ssl;
334
- fio_tls_s *tls;
335
- void *alpn_arg;
336
- intptr_t uuid;
337
- uint8_t is_server;
338
- volatile uint8_t alpn_ok;
339
- } fio_tls_connection_s;
340
-
341
- static void fio_tls_alpn_fallback(fio_tls_connection_s *c) {
342
- alpn_s *alpn = alpn_default(c->tls);
343
- if (!alpn || !alpn->on_selected)
344
- return;
345
- /* set protocol to default protocol */
346
- FIO_LOG_DEBUG("TLS ALPN handshake missing, falling back on %s for %p",
347
- fio_str_info(&alpn->name).data,
348
- (void *)c->uuid);
349
- alpn_select(alpn, c->uuid, c->alpn_arg);
350
- }
351
- static int fio_tls_alpn_selector_cb(SSL *ssl,
352
- const unsigned char **out,
353
- unsigned char *outlen,
354
- const unsigned char *in,
355
- unsigned int inlen,
356
- void *tls_) {
357
- fio_tls_s *tls = tls_;
358
- alpn_s *alpn;
359
- /* TODO: select ALPN and call on_selected */
360
- fio_tls_connection_s *c = SSL_get_ex_data(ssl, 0);
361
- c->alpn_ok = 1;
362
-
363
- if (alpn_list_count(&tls->alpn) == 0)
364
- return SSL_TLSEXT_ERR_NOACK;
365
- const unsigned char *end = in + inlen;
366
- while (in < end) {
367
- uint8_t l = in[0];
368
- alpn = alpn_find(tls, (char *)in + 1, l);
369
- in += l + 1;
370
- if (!alpn)
371
- continue;
372
- fio_str_info_s info = fio_str_info(&alpn->name);
373
- *out = (unsigned char *)info.data;
374
- *outlen = (unsigned char)info.len;
375
- FIO_LOG_DEBUG("TLS ALPN set to: %s for %p", info.data, (void *)c->uuid);
376
- alpn_select(alpn, c->uuid, c->alpn_arg);
377
- return SSL_TLSEXT_ERR_OK;
378
- }
379
- /* set protocol to default protocol */
380
- alpn = alpn_default(tls);
381
- alpn_select(alpn, c->uuid, c->alpn_arg);
382
- FIO_LOG_DEBUG(
383
- "TLS ALPN handshake failed, falling back on default (%s) for %p",
384
- fio_str_data(&alpn->name),
385
- (void *)c->uuid);
386
- return SSL_TLSEXT_ERR_NOACK;
387
- (void)ssl;
388
- (void)out;
389
- (void)outlen;
390
- (void)in;
391
- (void)inlen;
392
- (void)tls;
393
- }
394
-
395
- /** Called when the library specific data for the context should be destroyed */
396
- static void fio_tls_destroy_context(fio_tls_s *tls) {
397
- /* TODO: Library specific implementation */
398
- SSL_CTX_free(tls->ctx);
399
- free(tls->alpn_str);
400
-
401
- tls->ctx = NULL;
402
- tls->alpn_str = NULL;
403
- tls->alpn_len = 0;
404
- FIO_LOG_DEBUG("destroyed TLS context for OpenSSL %p", (void *)tls);
405
- }
406
-
407
- static int fio_tls_pem_passwd_cb(char *buf,
408
- int size,
409
- int rwflag,
410
- void *password) {
411
- fio_str_info_s *p = password;
412
- if (!p || !p->len || !size)
413
- return 0;
414
- int len = (size <= (int)p->len) ? (size - 1) : (int)p->len;
415
- memcpy(buf, p->data, len);
416
- buf[len] = 0;
417
- return len;
418
- (void)rwflag;
419
- }
420
-
421
- /** Called when the library specific data for the context should be built */
422
- static void fio_tls_build_context(fio_tls_s *tls) {
423
- fio_tls_destroy_context(tls);
424
- /* TODO: Library specific implementation */
425
-
426
- /* create new context */
427
- tls->ctx = SSL_CTX_new(TLS_method());
428
- SSL_CTX_set_mode(tls->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
429
- /* see: https://caniuse.com/#search=tls */
430
- SSL_CTX_set_min_proto_version(tls->ctx, TLS1_2_VERSION);
431
- SSL_CTX_set_options(tls->ctx, SSL_OP_NO_COMPRESSION);
432
-
433
- /* attach certificates */
434
- FIO_ARY_FOR(&tls->sni, pos) {
435
- fio_str_info_s keys[4] = {
436
- fio_str_info(&pos->private_key),
437
- fio_str_info(&pos->public_key),
438
- fio_str_info(&pos->password),
439
- /* empty password slot for public key */
440
- };
441
- if (keys[0].len && keys[1].len) {
442
- if (1) {
443
- /* Extract private key from private key file */
444
- BIO *bio = BIO_new_mem_buf(keys[0].data, keys[0].len);
445
- if (bio) {
446
- EVP_PKEY *k = PEM_read_bio_PrivateKey(bio,
447
- NULL,
448
- fio_tls_pem_passwd_cb,
449
- keys + 2);
450
- if (k) {
451
- FIO_LOG_DEBUG("TLS read private key from PEM file.");
452
- SSL_CTX_use_PrivateKey(tls->ctx, k);
453
- }
454
- BIO_free(bio);
455
- }
456
- }
457
- /* Certificate Files loaded */
458
- for (int ki = 0; ki < 2; ++ki) {
459
- /* Extract as much data as possible from each file */
460
- BIO *bio = BIO_new_mem_buf(keys[ki].data, keys[ki].len);
461
- FIO_ASSERT(bio, "OpenSSL error allocating BIO.");
462
- STACK_OF(X509_INFO) *inf = PEM_X509_INFO_read_bio(bio,
463
- NULL,
464
- fio_tls_pem_passwd_cb,
465
- keys + ki + 2);
466
- if (inf) {
467
- for (int i = 0; i < sk_X509_INFO_num(inf); ++i) {
468
- /* for each element in PEM */
469
- X509_INFO *tmp = sk_X509_INFO_value(inf, i);
470
- if (tmp->x509) {
471
- FIO_LOG_DEBUG("TLS adding certificate from PEM file.");
472
- if (i == 0) {
473
- SSL_CTX_use_certificate(tls->ctx, tmp->x509);
474
- } else {
475
- SSL_CTX_add1_chain_cert(tls->ctx, tmp->x509);
476
- }
477
- }
478
- if (tmp->x_pkey) {
479
- FIO_LOG_DEBUG("TLS adding private key from PEM file.");
480
- SSL_CTX_use_PrivateKey(tls->ctx, tmp->x_pkey->dec_pkey);
481
- }
482
- }
483
- sk_X509_INFO_pop_free(inf, X509_INFO_free);
484
- } else {
485
- /* TODO: attempt DER format? */
486
- // X509 *c;
487
- // EVP_PKEY *k;
488
- // const uint8_t *pdata = (uint8_t *)&keys[ki].data;
489
- // d2i_X509(&c, &pdata, keys[ki].len);
490
- // pdata = (uint8_t *)&keys[ki].data;
491
- // d2i_AutoPrivateKey(&k, &pdata, keys[ki].len);
492
- }
493
- BIO_free(bio);
494
- }
495
- } else if (keys[0].len) {
496
- /* Self Signed Certificates, only if server name is provided. */
497
- SSL_CTX_use_certificate(tls->ctx,
498
- fio_tls_create_self_signed(keys[0].data));
499
- SSL_CTX_use_PrivateKey(tls->ctx, fio_tls_pkey);
500
- }
501
- }
502
-
503
- /* setup ALPN support */
504
- if (1) {
505
- size_t alpn_pos = 0;
506
- /* looping twice is better than malloc fragmentation. */
507
- FIO_SET_FOR_LOOP(&tls->alpn, pos) {
508
- fio_str_info_s s = fio_str_info(&pos->obj.name);
509
- if (!s.len)
510
- continue;
511
- alpn_pos += s.len + 1;
512
- }
513
- tls->alpn_str = malloc((alpn_pos | 15) + 1); /* round up to 16 + padding */
514
- alpn_pos = 0;
515
- FIO_SET_FOR_LOOP(&tls->alpn, pos) {
516
- fio_str_info_s s = fio_str_info(&pos->obj.name);
517
- if (!s.len)
518
- continue;
519
- tls->alpn_str[alpn_pos++] = (uint8_t)s.len;
520
- memcpy(tls->alpn_str + alpn_pos, s.data, s.len);
521
- alpn_pos += s.len;
522
- }
523
- tls->alpn_len = alpn_pos;
524
- SSL_CTX_set_alpn_select_cb(tls->ctx, fio_tls_alpn_selector_cb, tls);
525
- SSL_CTX_set_alpn_protos(tls->ctx, tls->alpn_str, tls->alpn_len);
526
- }
527
-
528
- /* Peer Verification / Trust */
529
- if (trust_ary_count(&tls->trust)) {
530
- /* TODO: enable peer verification */
531
- X509_STORE *store = X509_STORE_new();
532
- SSL_CTX_set_cert_store(tls->ctx, store);
533
- SSL_CTX_set_verify(tls->ctx, SSL_VERIFY_PEER, NULL);
534
- /* TODO: Add each ceriticate in the PEM to the trust "store" */
535
- FIO_ARY_FOR(&tls->trust, pos) {
536
- fio_str_info_s pem = fio_str_info(&pos->pem);
537
- BIO *bio = BIO_new_mem_buf(pem.data, pem.len);
538
- FIO_ASSERT(bio, "OpenSSL error allocating BIO.");
539
- STACK_OF(X509_INFO) *inf = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
540
- if (inf) {
541
- for (int i = 0; i < sk_X509_INFO_num(inf); ++i) {
542
- /* for each element in PEM */
543
- X509_INFO *tmp = sk_X509_INFO_value(inf, i);
544
- if (tmp->x509) {
545
- FIO_LOG_DEBUG("TLS trusting certificate from PEM file.");
546
- X509_STORE_add_cert(store, tmp->x509);
547
- }
548
- if (tmp->crl) {
549
- X509_STORE_add_crl(store, tmp->crl);
550
- }
551
- }
552
- sk_X509_INFO_pop_free(inf, X509_INFO_free);
553
- }
554
- BIO_free(bio);
555
- }
556
- }
557
-
558
- FIO_LOG_DEBUG("(re)built TLS context for OpenSSL %p", (void *)tls);
559
- }
560
-
561
- /* *****************************************************************************
562
- SSL/TLS RW Hooks
563
- ***************************************************************************** */
564
-
565
- static void fio_tls_delayed_close(void *uuid, void *ignr_) {
566
- fio_close((intptr_t)uuid);
567
- (void)ignr_;
568
- }
569
-
570
- /* TODO: this is an example implementation - fix for specific library. */
571
-
572
- /**
573
- * Implement reading from a file descriptor. Should behave like the file
574
- * system `read` call, including the setup or errno to EAGAIN / EWOULDBLOCK.
575
- *
576
- * Note: facil.io library functions MUST NEVER be called by any r/w hook, or a
577
- * deadlock might occur.
578
- */
579
- static ssize_t fio_tls_read(intptr_t uuid,
580
- void *udata,
581
- void *buf,
582
- size_t count) {
583
- fio_tls_connection_s *c = udata;
584
- ssize_t ret = SSL_read(c->ssl, buf, count);
585
- if (ret > 0)
586
- return ret;
587
- ret = SSL_get_error(c->ssl, ret);
588
- switch (ret) {
589
- case SSL_ERROR_SSL: /* overflow */
590
- case SSL_ERROR_ZERO_RETURN: return 0; /* EOF */
591
- case SSL_ERROR_SYSCALL: /* allow errno to inform us */ break; /* return -1 */
592
- case SSL_ERROR_NONE: /* overflow */
593
- case SSL_ERROR_WANT_CONNECT: /* overflow */
594
- case SSL_ERROR_WANT_ACCEPT: /* overflow */
595
- case SSL_ERROR_WANT_X509_LOOKUP: /* overflow */
596
- case SSL_ERROR_WANT_WRITE: /* overflow */
597
- case SSL_ERROR_WANT_READ: /* overflow */
598
- #ifdef SSL_ERROR_WANT_ASYNC
599
- case SSL_ERROR_WANT_ASYNC: /* overflow */
600
- #endif
601
- default: errno = EWOULDBLOCK; break;
602
- }
603
- return -1;
604
- (void)uuid;
605
- }
606
-
607
- /**
608
- * When implemented, this function will be called to flush any data remaining
609
- * in the internal buffer.
610
- *
611
- * The function should return the number of bytes remaining in the internal
612
- * buffer (0 is a valid response) or -1 (on error).
613
- *
614
- * Note: facil.io library functions MUST NEVER be called by any r/w hook, or a
615
- * deadlock might occur.
616
- */
617
- static ssize_t fio_tls_flush(intptr_t uuid, void *udata) {
618
- (void)uuid;
619
- (void)udata;
620
- return 0;
621
- }
622
-
623
- /**
624
- * Implement writing to a file descriptor. Should behave like the file system
625
- * `write` call.
626
- *
627
- * If an internal buffer is implemented and it is full, errno should be set to
628
- * EWOULDBLOCK and the function should return -1.
629
- *
630
- * Note: facil.io library functions MUST NEVER be called by any r/w hook, or a
631
- * deadlock might occur.
632
- */
633
- static ssize_t fio_tls_write(intptr_t uuid,
634
- void *udata,
635
- const void *buf,
636
- size_t count) {
637
- fio_tls_connection_s *c = udata;
638
- ssize_t ret = SSL_write(c->ssl, buf, count);
639
- if (ret > 0)
640
- return ret;
641
- ret = SSL_get_error(c->ssl, ret);
642
- switch (ret) {
643
- case SSL_ERROR_SSL: /* overflow */
644
- case SSL_ERROR_ZERO_RETURN: return 0; /* EOF */
645
- case SSL_ERROR_SYSCALL: /* allow errno to inform us */ break; /* return -1 */
646
- case SSL_ERROR_NONE: /* overflow */
647
- case SSL_ERROR_WANT_CONNECT: /* overflow */
648
- case SSL_ERROR_WANT_ACCEPT: /* overflow */
649
- case SSL_ERROR_WANT_X509_LOOKUP: /* overflow */
650
- case SSL_ERROR_WANT_WRITE: /* overflow */
651
- case SSL_ERROR_WANT_READ: /* overflow */
652
- #ifdef SSL_ERROR_WANT_ASYNC
653
- case SSL_ERROR_WANT_ASYNC: /* overflow */
654
- #endif
655
- default: errno = EWOULDBLOCK; break;
656
- }
657
- return -1;
658
- (void)uuid;
659
- }
660
-
661
- /**
662
- * The `close` callback should close the underlying socket / file descriptor.
663
- *
664
- * If the function returns a non-zero value, it will be called again after an
665
- * attempt to flush the socket and any pending outgoing buffer.
666
- *
667
- * Note: facil.io library functions MUST NEVER be called by any r/w hook, or a
668
- * deadlock might occur.
669
- * */
670
- static ssize_t fio_tls_before_close(intptr_t uuid, void *udata) {
671
- fio_tls_connection_s *c = udata;
672
- SSL_shutdown(c->ssl);
673
- return 1;
674
- (void)uuid;
675
- }
676
- /**
677
- * Called to perform cleanup after the socket was closed.
678
- * */
679
- static void fio_tls_cleanup(void *udata) {
680
- fio_tls_connection_s *c = udata;
681
- if (!c->alpn_ok) {
682
- alpn_select(alpn_default(c->tls), -1, c->alpn_arg);
683
- }
684
- SSL_free(c->ssl);
685
- FIO_LOG_DEBUG("TLS cleanup for %p", (void *)c->uuid);
686
- fio_tls_destroy(c->tls); /* manage reference count */
687
- free(udata);
688
- }
689
-
690
- static fio_rw_hook_s FIO_TLS_HOOKS = {
691
- .read = fio_tls_read,
692
- .write = fio_tls_write,
693
- .flush = fio_tls_flush,
694
- .before_close = fio_tls_before_close,
695
- .cleanup = fio_tls_cleanup,
696
- };
697
-
698
- #define FIO_TLS_HANDSHAKE_ERROR 0
699
- #define FIO_TLS_HANDSHAKE_OK 1
700
- #define FIO_TLS_HANDSHAKE_NEED_READ 2
701
- #define FIO_TLS_HANDSHAKE_NEED_WRITE 4
702
-
703
- static size_t fio_tls_handshake(intptr_t uuid, void *udata) {
704
- size_t status = FIO_TLS_HANDSHAKE_ERROR;
705
- fio_tls_connection_s *c = udata;
706
-
707
- int ri;
708
- if (c->is_server) {
709
- ri = SSL_accept(c->ssl);
710
- } else {
711
- ri = SSL_connect(c->ssl);
712
- }
713
- if (ri != 1) {
714
- ri = SSL_get_error(c->ssl, ri);
715
- switch (ri) {
716
- case SSL_ERROR_NONE:
717
- // FIO_LOG_DEBUG("SSL_accept/SSL_connect %p state: SSL_ERROR_NONE",
718
- // (void *)uuid);
719
- status = FIO_TLS_HANDSHAKE_NEED_READ | FIO_TLS_HANDSHAKE_NEED_WRITE;
720
- return status;
721
- case SSL_ERROR_WANT_WRITE:
722
- // FIO_LOG_DEBUG("SSL_accept/SSL_connect %p state: SSL_ERROR_WANT_WRITE",
723
- // (void *)uuid);
724
- status = FIO_TLS_HANDSHAKE_NEED_WRITE;
725
- return status;
726
- case SSL_ERROR_WANT_READ:
727
- // FIO_LOG_DEBUG("SSL_accept/SSL_connect %p state: SSL_ERROR_WANT_READ",
728
- // (void *)uuid);
729
- status = FIO_TLS_HANDSHAKE_NEED_READ;
730
- return status;
731
- case SSL_ERROR_SYSCALL:
732
- if (errno) {
733
- FIO_LOG_DEBUG(
734
- "SSL_accept/SSL_connect %p error: SSL_ERROR_SYSCALL, errno: %s",
735
- (void *)uuid,
736
- strerror(errno));
737
- }
738
- break;
739
- case SSL_ERROR_SSL:
740
- FIO_LOG_DEBUG(
741
- "SSL_accept/SSL_connect %p error: SSL_ERROR_SSL (non SSL attempt?)",
742
- (void *)uuid);
743
- break;
744
- case SSL_ERROR_ZERO_RETURN:
745
- FIO_LOG_DEBUG("SSL_accept/SSL_connect %p error: SSL_ERROR_ZERO_RETURN",
746
- (void *)uuid);
747
- break;
748
- case SSL_ERROR_WANT_CONNECT:
749
- FIO_LOG_DEBUG("SSL_accept/SSL_connect %p error: SSL_ERROR_WANT_CONNECT",
750
- (void *)uuid);
751
- break;
752
- case SSL_ERROR_WANT_ACCEPT:
753
- FIO_LOG_DEBUG("SSL_accept/SSL_connect %p error: SSL_ERROR_WANT_ACCEPT",
754
- (void *)uuid);
755
- break;
756
- case SSL_ERROR_WANT_X509_LOOKUP:
757
- FIO_LOG_DEBUG(
758
- "SSL_accept/SSL_connect %p error: SSL_ERROR_WANT_X509_LOOKUP",
759
- (void *)uuid);
760
- break;
761
- #ifdef SSL_ERROR_WANT_ASYNC
762
- case SSL_ERROR_WANT_ASYNC:
763
- FIO_LOG_DEBUG("SSL_accept/SSL_connect %p error: SSL_ERROR_WANT_ASYNC",
764
- (void *)uuid);
765
- break;
766
- #endif
767
- #ifdef SSL_ERROR_WANT_CLIENT_HELLO_CB
768
- case SSL_ERROR_WANT_CLIENT_HELLO_CB:
769
- FIO_LOG_DEBUG(
770
- "SSL_accept/SSL_connect %p error: SSL_ERROR_WANT_CLIENT_HELLO_CB",
771
- (void *)uuid);
772
- break;
773
- #endif
774
- default:
775
- FIO_LOG_DEBUG("SSL_accept/SSL_connect %p error: unknown (%d).",
776
- (void *)uuid,
777
- ri);
778
- break;
779
- }
780
- fio_rw_hook_replace_unsafe(uuid, &FIO_TLS_HOOKS, udata);
781
- fio_defer(fio_tls_delayed_close, (void *)uuid, NULL);
782
- return status;
783
- }
784
- if (!c->alpn_ok) {
785
- c->alpn_ok = 1;
786
- if (c->is_server) {
787
- fio_tls_alpn_fallback(c);
788
- } else {
789
- const unsigned char *proto;
790
- unsigned int proto_len;
791
- SSL_get0_alpn_selected(c->ssl, &proto, &proto_len);
792
- alpn_s *alpn = NULL;
793
- if (proto_len > 0) {
794
- alpn = alpn_find(c->tls, (char *)proto, proto_len);
795
- }
796
- if (!alpn) {
797
- alpn = alpn_default(c->tls);
798
- FIO_LOG_DEBUG("ALPN missing for TLS client %p", (void *)uuid);
799
- }
800
- if (alpn)
801
- FIO_LOG_DEBUG("setting ALPN %s for TLS client %p",
802
- fio_str_data(&alpn->name),
803
- (void *)uuid);
804
- alpn_select(alpn, c->uuid, c->alpn_arg);
805
- }
806
- }
807
- if (fio_rw_hook_replace_unsafe(uuid, &FIO_TLS_HOOKS, udata) == 0) {
808
- FIO_LOG_DEBUG("Completed TLS handshake for %p", (void *)uuid);
809
- } else {
810
- FIO_LOG_DEBUG("Something went wrong during TLS handshake for %p",
811
- (void *)uuid);
812
- return status;
813
- }
814
- /* make sure the connection is re-added to the reactor */
815
- fio_force_event(uuid, FIO_EVENT_ON_DATA);
816
- /* log session ID for WireShark */
817
- #if FIO_TLS_PRINT_SECRET
818
- if (FIO_LOG_LEVEL >= FIO_LOG_LEVEL_DEBUG) {
819
- unsigned char buff[SSL_MAX_MASTER_KEY_LENGTH + 2];
820
- size_t ret = SSL_SESSION_get_master_key(SSL_get_session(c->ssl),
821
- buff,
822
- SSL_MAX_MASTER_KEY_LENGTH + 1);
823
- buff[ret] = 0;
824
- unsigned char buff2[(SSL_MAX_MASTER_KEY_LENGTH + 2) << 1];
825
- for (size_t i = 0; i < ret; ++i) {
826
- buff2[i] = ((buff[i] >> 4) >= 10) ? ('A' + (buff[i] >> 4) - 10)
827
- : ('0' + (buff[i] >> 4));
828
- buff2[i + 1] = ((buff[i] & 15) >= 10) ? ('A' + (buff[i] & 15) - 10)
829
- : ('0' + (buff[i] & 15));
830
- }
831
- buff2[(ret << 1)] = 0;
832
- FIO_LOG_DEBUG("OpenSSL Master Key for uuid %p:\n\t\t%s",
833
- (void *)uuid,
834
- buff2);
835
- }
836
- #endif
837
- status = FIO_TLS_HANDSHAKE_OK;
838
- return status;
839
- }
840
-
841
- static ssize_t fio_tls_read4handshake(intptr_t uuid,
842
- void *udata,
843
- void *buf,
844
- size_t count) {
845
- // FIO_LOG_DEBUG("TLS handshake from read %p", (void *)uuid);
846
- size_t s = fio_tls_handshake(uuid, udata);
847
- if (s == FIO_TLS_HANDSHAKE_OK)
848
- return fio_tls_read(uuid, udata, buf, count);
849
- if (!s)
850
- return 0;
851
- errno = EWOULDBLOCK;
852
- return -1;
853
- }
854
-
855
- static ssize_t fio_tls_write4handshake(intptr_t uuid,
856
- void *udata,
857
- const void *buf,
858
- size_t count) {
859
- // FIO_LOG_DEBUG("TLS handshake from write %p", (void *)uuid);
860
- size_t s = fio_tls_handshake(uuid, udata);
861
- if (s == FIO_TLS_HANDSHAKE_OK)
862
- return fio_tls_write(uuid, udata, buf, count);
863
- if (!s)
864
- return 0;
865
- errno = EWOULDBLOCK;
866
- return -1;
867
- }
868
-
869
- static ssize_t fio_tls_flush4handshake(intptr_t uuid, void *udata) {
870
- // FIO_LOG_DEBUG("TLS handshake from flush %p", (void *)uuid);
871
- size_t s = fio_tls_handshake(uuid, udata);
872
- if (s == FIO_TLS_HANDSHAKE_OK) {
873
- return fio_tls_flush(uuid, udata);
874
- }
875
- if (!s)
876
- return 0;
877
- errno = 0;
878
- return s | FIO_TLS_HANDSHAKE_NEED_WRITE;
879
- }
880
-
881
- static fio_rw_hook_s FIO_TLS_HANDSHAKE_HOOKS = {
882
- .read = fio_tls_read4handshake,
883
- .write = fio_tls_write4handshake,
884
- .before_close = fio_tls_before_close,
885
- .flush = fio_tls_flush4handshake,
886
- .cleanup = fio_tls_cleanup,
887
- };
888
- static inline void fio_tls_attach2uuid(intptr_t uuid,
889
- fio_tls_s *tls,
890
- void *udata,
891
- uint8_t is_server) {
892
- fio_atomic_add(&tls->ref, 1);
893
- /* create SSL connection context from global context */
894
- fio_tls_connection_s *c = malloc(sizeof(*c));
895
- FIO_ASSERT_ALLOC(c);
896
- *c = (fio_tls_connection_s){
897
- .alpn_arg = udata,
898
- .tls = tls,
899
- .uuid = uuid,
900
- .ssl = SSL_new(tls->ctx),
901
- .is_server = is_server,
902
- .alpn_ok = 0,
903
- };
904
- FIO_ASSERT_ALLOC(c->ssl);
905
- /* set facil.io data in the SSL object */
906
- SSL_set_ex_data(c->ssl, 0, (void *)c);
907
- /* attach socket - TODO: Switch to BIO socket */
908
- BIO *bio = BIO_new_socket(fio_uuid2fd(uuid), 0);
909
- BIO_up_ref(bio);
910
- SSL_set0_rbio(c->ssl, bio);
911
- SSL_set0_wbio(c->ssl, bio);
912
- /* set RW hooks */
913
- fio_rw_hook_set(uuid, &FIO_TLS_HANDSHAKE_HOOKS, c);
914
- if (is_server) {
915
- /* Server mode (accept) */
916
- FIO_LOG_DEBUG("Attaching TLS read/write hook for %p (server mode).",
917
- (void *)uuid);
918
- SSL_set_accept_state(c->ssl);
919
- } else {
920
- /* Client mode (connect) */
921
- FIO_LOG_DEBUG("Attaching TLS read/write hook for %p (client mode).",
922
- (void *)uuid);
923
- SSL_set_connect_state(c->ssl);
924
- }
925
- fio_force_event(uuid, FIO_EVENT_ON_READY);
926
- }
927
-
928
- /* *****************************************************************************
929
- SSL/TLS API implementation - this can be pretty much used as is...
930
- ***************************************************************************** */
931
-
932
- /**
933
- * Creates a new SSL/TLS context / settings object with a default certificate
934
- * (if any).
935
- */
936
- fio_tls_s *FIO_TLS_WEAK fio_tls_new(const char *server_name,
937
- const char *cert,
938
- const char *key,
939
- const char *pk_password) {
940
- REQUIRE_LIBRARY();
941
- fio_tls_s *tls = calloc(sizeof(*tls), 1);
942
- tls->ref = 1;
943
- fio_tls_cert_add(tls, server_name, key, cert, pk_password);
944
- return tls;
945
- }
946
-
947
- /**
948
- * Adds a certificate a new SSL/TLS context / settings object.
949
- */
950
- void FIO_TLS_WEAK fio_tls_cert_add(fio_tls_s *tls,
951
- const char *server_name,
952
- const char *cert,
953
- const char *key,
954
- const char *pk_password) {
955
- REQUIRE_LIBRARY();
956
- cert_s c = {
957
- .private_key = FIO_STR_INIT,
958
- .public_key = FIO_STR_INIT,
959
- .password = FIO_STR_INIT_STATIC2(pk_password,
960
- (pk_password ? strlen(pk_password) : 0)),
961
- };
962
- if (key && cert) {
963
- if (fio_str_readfile(&c.private_key, key, 0, 0).data == NULL)
964
- goto file_missing;
965
- if (fio_str_readfile(&c.public_key, cert, 0, 0).data == NULL)
966
- goto file_missing;
967
- cert_ary_push(&tls->sni, c);
968
- } else if (server_name) {
969
- /* Self-Signed TLS Certificates */
970
- c.private_key = FIO_STR_INIT_STATIC(server_name);
971
- cert_ary_push(&tls->sni, c);
972
- }
973
- fio_tls_cert_destroy(&c);
974
- fio_tls_build_context(tls);
975
- return;
976
- file_missing:
977
- FIO_LOG_FATAL("TLS certificate file missing for either %s or %s or both.",
978
- key,
979
- cert);
980
- exit(-1);
981
- }
982
-
983
- /**
984
- * Adds an ALPN protocol callback to the SSL/TLS context.
985
- *
986
- * The first protocol added will act as the default protocol to be selected.
987
- *
988
- * The callback should accept the `uuid`, the user data pointer passed to
989
- * either `fio_tls_accept` or `fio_tls_connect` (here: `udata_connetcion`) and
990
- * the user data pointer passed to the `fio_tls_alpn_add` function
991
- * (`udata_tls`).
992
- *
993
- * The `on_cleanup` callback will be called when the TLS object is destroyed
994
- * (or `fio_tls_alpn_add` is called again with the same protocol name). The
995
- * `udata_tls` argumrnt will be passed along, as is, to the callback (if set).
996
- *
997
- * Except for the `tls` and `protocol_name` arguments, all arguments can be
998
- * NULL.
999
- */
1000
- void FIO_TLS_WEAK fio_tls_alpn_add(fio_tls_s *tls,
1001
- const char *protocol_name,
1002
- void (*on_selected)(intptr_t uuid,
1003
- void *udata_connection,
1004
- void *udata_tls),
1005
- void *udata_tls,
1006
- void (*on_cleanup)(void *udata_tls)) {
1007
- REQUIRE_LIBRARY();
1008
- alpn_add(tls, protocol_name, on_selected, udata_tls, on_cleanup);
1009
- fio_tls_build_context(tls);
1010
- }
1011
-
1012
- /**
1013
- * Returns the number of registered ALPN protocol names.
1014
- *
1015
- * This could be used when deciding if protocol selection should be delegated
1016
- * to the ALPN mechanism, or whether a protocol should be immediately
1017
- * assigned.
1018
- *
1019
- * If no ALPN protocols are registered, zero (0) is returned.
1020
- */
1021
- uintptr_t FIO_TLS_WEAK fio_tls_alpn_count(fio_tls_s *tls) {
1022
- return tls ? alpn_list_count(&tls->alpn) : 0;
1023
- }
1024
-
1025
- /**
1026
- * Adds a certificate to the "trust" list, which automatically adds a peer
1027
- * verification requirement.
1028
- *
1029
- * fio_tls_trust(tls, "google-ca.pem" );
1030
- */
1031
- void FIO_TLS_WEAK fio_tls_trust(fio_tls_s *tls, const char *public_cert_file) {
1032
- REQUIRE_LIBRARY();
1033
- trust_s c = {
1034
- .pem = FIO_STR_INIT,
1035
- };
1036
- if (!public_cert_file)
1037
- return;
1038
- if (fio_str_readfile(&c.pem, public_cert_file, 0, 0).data == NULL)
1039
- goto file_missing;
1040
- trust_ary_push(&tls->trust, c);
1041
- fio_tls_trust_destroy(&c);
1042
- fio_tls_build_context(tls);
1043
- return;
1044
- file_missing:
1045
- FIO_LOG_FATAL("TLS certificate file missing for %s ", public_cert_file);
1046
- exit(-1);
1047
- }
1048
-
1049
- /**
1050
- * Establishes an SSL/TLS connection as an SSL/TLS Server, using the specified
1051
- * context / settings object.
1052
- *
1053
- * The `uuid` should be a socket UUID that is already connected to a peer
1054
- * (i.e., the result of `fio_accept`).
1055
- *
1056
- * The `udata` is an opaque user data pointer that is passed along to the
1057
- * protocol selected (if any protocols were added using `fio_tls_alpn_add`).
1058
- */
1059
- void FIO_TLS_WEAK fio_tls_accept(intptr_t uuid, fio_tls_s *tls, void *udata) {
1060
- REQUIRE_LIBRARY();
1061
- fio_timeout_set(uuid, FIO_TLS_TIMEOUT);
1062
- fio_tls_attach2uuid(uuid, tls, udata, 1);
1063
- }
1064
-
1065
- /**
1066
- * Establishes an SSL/TLS connection as an SSL/TLS Client, using the specified
1067
- * context / settings object.
1068
- *
1069
- * The `uuid` should be a socket UUID that is already connected to a peer
1070
- * (i.e., one received by a `fio_connect` specified callback `on_connect`).
1071
- *
1072
- * The `udata` is an opaque user data pointer that is passed along to the
1073
- * protocol selected (if any protocols were added using `fio_tls_alpn_add`).
1074
- */
1075
- void FIO_TLS_WEAK fio_tls_connect(intptr_t uuid, fio_tls_s *tls, void *udata) {
1076
- REQUIRE_LIBRARY();
1077
- fio_tls_attach2uuid(uuid, tls, udata, 0);
1078
- }
1079
-
1080
- /**
1081
- * Increase the reference count for the TLS object.
1082
- *
1083
- * Decrease with `fio_tls_destroy`.
1084
- */
1085
- void FIO_TLS_WEAK fio_tls_dup(fio_tls_s *tls) { fio_atomic_add(&tls->ref, 1); }
1086
-
1087
- /**
1088
- * Destroys the SSL/TLS context / settings object and frees any related
1089
- * resources / memory.
1090
- */
1091
- void FIO_TLS_WEAK fio_tls_destroy(fio_tls_s *tls) {
1092
- if (!tls)
1093
- return;
1094
- REQUIRE_LIBRARY();
1095
- if (fio_atomic_sub(&tls->ref, 1))
1096
- return;
1097
- fio_tls_destroy_context(tls);
1098
- alpn_list_free(&tls->alpn);
1099
- cert_ary_free(&tls->sni);
1100
- trust_ary_free(&tls->trust);
1101
- free(tls);
1102
- FIO_LOG_DEBUG("freed TLS context %p", (void *)tls);
1103
- }
1104
-
1105
- #endif /* Library compiler flags */
1106
- #endif