trilogy_w_prepared_statements 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +80 -0
  4. data/Rakefile +22 -0
  5. data/ext/trilogy-ruby/cast.c +277 -0
  6. data/ext/trilogy-ruby/cext.c +1048 -0
  7. data/ext/trilogy-ruby/extconf.rb +17 -0
  8. data/ext/trilogy-ruby/inc/trilogy/blocking.h +281 -0
  9. data/ext/trilogy-ruby/inc/trilogy/buffer.h +64 -0
  10. data/ext/trilogy-ruby/inc/trilogy/builder.h +165 -0
  11. data/ext/trilogy-ruby/inc/trilogy/charset.h +277 -0
  12. data/ext/trilogy-ruby/inc/trilogy/client.h +760 -0
  13. data/ext/trilogy-ruby/inc/trilogy/error.h +44 -0
  14. data/ext/trilogy-ruby/inc/trilogy/packet_parser.h +34 -0
  15. data/ext/trilogy-ruby/inc/trilogy/protocol.h +1014 -0
  16. data/ext/trilogy-ruby/inc/trilogy/reader.h +216 -0
  17. data/ext/trilogy-ruby/inc/trilogy/socket.h +111 -0
  18. data/ext/trilogy-ruby/inc/trilogy/vendor/curl_hostcheck.h +29 -0
  19. data/ext/trilogy-ruby/inc/trilogy/vendor/openssl_hostname_validation.h +51 -0
  20. data/ext/trilogy-ruby/inc/trilogy.h +8 -0
  21. data/ext/trilogy-ruby/src/blocking.c +358 -0
  22. data/ext/trilogy-ruby/src/buffer.c +60 -0
  23. data/ext/trilogy-ruby/src/builder.c +236 -0
  24. data/ext/trilogy-ruby/src/charset.c +212 -0
  25. data/ext/trilogy-ruby/src/client.c +903 -0
  26. data/ext/trilogy-ruby/src/error.c +17 -0
  27. data/ext/trilogy-ruby/src/packet_parser.c +140 -0
  28. data/ext/trilogy-ruby/src/protocol.c +1175 -0
  29. data/ext/trilogy-ruby/src/reader.c +282 -0
  30. data/ext/trilogy-ruby/src/socket.c +623 -0
  31. data/ext/trilogy-ruby/src/vendor/curl_hostcheck.c +206 -0
  32. data/ext/trilogy-ruby/src/vendor/openssl_hostname_validation.c +175 -0
  33. data/ext/trilogy-ruby/trilogy-ruby.h +37 -0
  34. data/lib/trilogy/version.rb +3 -0
  35. data/lib/trilogy.rb +61 -0
  36. data/trilogy.gemspec +27 -0
  37. metadata +107 -0
@@ -0,0 +1,623 @@
1
+ #include <netdb.h>
2
+ #include <netinet/tcp.h>
3
+ #include <poll.h>
4
+ #include <sys/socket.h>
5
+ #include <sys/types.h>
6
+ #include <sys/un.h>
7
+
8
+ #include <errno.h>
9
+ #include <fcntl.h>
10
+ #include <stdlib.h>
11
+ #include <unistd.h>
12
+
13
+ #include "trilogy/error.h"
14
+ #include "trilogy/socket.h"
15
+
16
+ #if OPENSSL_VERSION_NUMBER < 0x1000200fL
17
+ #include "trilogy/vendor/openssl_hostname_validation.h"
18
+ #endif
19
+
20
+ struct trilogy_sock {
21
+ trilogy_sock_t base;
22
+ struct addrinfo *addr;
23
+ int fd;
24
+ SSL *ssl;
25
+ };
26
+
27
+ static int _cb_raw_fd(trilogy_sock_t *_sock)
28
+ {
29
+ struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
30
+ return sock->fd;
31
+ }
32
+
33
+ static int _cb_wait(trilogy_sock_t *_sock, trilogy_wait_t wait)
34
+ {
35
+ struct pollfd pfd = {.fd = trilogy_sock_fd(_sock)};
36
+
37
+ switch (wait) {
38
+ case TRILOGY_WAIT_HANDSHAKE:
39
+ case TRILOGY_WAIT_READ:
40
+ pfd.events = POLLIN;
41
+ break;
42
+ case TRILOGY_WAIT_WRITE:
43
+ pfd.events = POLLOUT;
44
+ break;
45
+ default:
46
+ return TRILOGY_ERR;
47
+ }
48
+
49
+ while (1) {
50
+ int rc = poll(&pfd, 1, -1);
51
+
52
+ if (rc < 0) {
53
+ if (errno == EINTR) {
54
+ continue;
55
+ }
56
+ return TRILOGY_SYSERR;
57
+ }
58
+
59
+ return TRILOGY_OK;
60
+ }
61
+ }
62
+
63
+ static ssize_t _cb_raw_read(trilogy_sock_t *_sock, void *buf, size_t nread)
64
+ {
65
+ struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
66
+ ssize_t data_read = read(sock->fd, buf, nread);
67
+ if (data_read < 0) {
68
+ return (ssize_t)TRILOGY_SYSERR;
69
+ }
70
+ return data_read;
71
+ }
72
+
73
+ static ssize_t _cb_raw_write(trilogy_sock_t *_sock, const void *buf, size_t nwrite)
74
+ {
75
+ struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
76
+ ssize_t data_written = write(sock->fd, buf, nwrite);
77
+ if (data_written < 0) {
78
+ return (ssize_t)TRILOGY_SYSERR;
79
+ }
80
+ return data_written;
81
+ }
82
+
83
+ static int _cb_raw_close(trilogy_sock_t *_sock)
84
+ {
85
+ struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
86
+ int rc = 0;
87
+ if (sock->fd != -1) {
88
+ rc = close(sock->fd);
89
+ }
90
+ if (sock->addr) {
91
+ freeaddrinfo(sock->addr);
92
+ }
93
+
94
+ free(sock->base.opts.hostname);
95
+ free(sock->base.opts.path);
96
+ free(sock->base.opts.database);
97
+ free(sock->base.opts.username);
98
+ free(sock->base.opts.password);
99
+ free(sock->base.opts.ssl_ca);
100
+ free(sock->base.opts.ssl_capath);
101
+ free(sock->base.opts.ssl_cert);
102
+ free(sock->base.opts.ssl_cipher);
103
+ free(sock->base.opts.ssl_crl);
104
+ free(sock->base.opts.ssl_crlpath);
105
+ free(sock->base.opts.ssl_key);
106
+ free(sock->base.opts.tls_ciphersuites);
107
+
108
+ free(sock);
109
+ return rc;
110
+ }
111
+
112
+ static int _cb_raw_shutdown(trilogy_sock_t *_sock) { return shutdown(trilogy_sock_fd(_sock), SHUT_RDWR); }
113
+
114
+ static int set_nonblocking_fd(int sock)
115
+ {
116
+ int flags = fcntl(sock, F_GETFL, 0);
117
+
118
+ if (flags < 0) {
119
+ return TRILOGY_SYSERR;
120
+ }
121
+
122
+ if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) {
123
+ return TRILOGY_SYSERR;
124
+ }
125
+
126
+ return TRILOGY_OK;
127
+ }
128
+
129
+ static int raw_connect_internal(struct trilogy_sock *sock, const struct addrinfo *ai)
130
+ {
131
+ int sockerr;
132
+ socklen_t sockerr_len = sizeof(sockerr);
133
+
134
+ sock->fd = socket(ai->ai_family, SOCK_STREAM, ai->ai_protocol);
135
+ if (sock->fd < 0) {
136
+ return TRILOGY_SYSERR;
137
+ }
138
+
139
+ if (sock->base.opts.keepalive_enabled) {
140
+ int flags = 1;
141
+ if (setsockopt(sock->fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags)) < 0) {
142
+ goto fail;
143
+ }
144
+ #ifdef TCP_KEEPIDLE
145
+ if (sock->base.opts.keepalive_idle > 0) {
146
+ flags = sock->base.opts.keepalive_idle;
147
+ if (setsockopt(sock->fd, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&flags, sizeof(flags)) < 0) {
148
+ goto fail;
149
+ }
150
+ }
151
+ #endif
152
+ #ifdef TCP_KEEPINTVL
153
+ if (sock->base.opts.keepalive_interval > 0) {
154
+ flags = sock->base.opts.keepalive_interval;
155
+ if (setsockopt(sock->fd, IPPROTO_TCP, TCP_KEEPINTVL, (void *)&flags, sizeof(flags)) < 0) {
156
+ goto fail;
157
+ }
158
+ }
159
+ #endif
160
+ #ifdef TCP_KEEPCNT
161
+ if (sock->base.opts.keepalive_count > 0) {
162
+ flags = sock->base.opts.keepalive_count;
163
+ if (setsockopt(sock->fd, IPPROTO_TCP, TCP_KEEPCNT, (void *)&flags, sizeof(flags)) < 0) {
164
+ goto fail;
165
+ }
166
+ }
167
+ #endif
168
+ }
169
+
170
+ if (set_nonblocking_fd(sock->fd) < 0) {
171
+ goto fail;
172
+ }
173
+
174
+ if (connect(sock->fd, ai->ai_addr, ai->ai_addrlen) < 0) {
175
+ if (errno != EINPROGRESS && errno != EAGAIN) {
176
+ goto fail;
177
+ }
178
+ }
179
+
180
+ if (trilogy_sock_wait_write((trilogy_sock_t *)sock) < 0) {
181
+ goto fail;
182
+ }
183
+
184
+ if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &sockerr, &sockerr_len) < 0) {
185
+ goto fail;
186
+ }
187
+
188
+ if (sockerr != 0) {
189
+ // the socket failed to connect; since `getsockopt` doesn't set `errno`
190
+ // to a meaningful value, we must set it manually because clients always
191
+ // expect to find the error code there
192
+ errno = sockerr;
193
+ goto fail;
194
+ }
195
+
196
+ return TRILOGY_OK;
197
+
198
+ fail:
199
+ close(sock->fd);
200
+ sock->fd = -1;
201
+ return TRILOGY_SYSERR;
202
+ }
203
+
204
+ static int _cb_raw_connect(trilogy_sock_t *_sock)
205
+ {
206
+ struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
207
+ const struct addrinfo *ai = sock->addr;
208
+
209
+ for (; ai; ai = ai->ai_next) {
210
+ int rc = raw_connect_internal(sock, ai);
211
+ if (rc == TRILOGY_OK)
212
+ return TRILOGY_OK;
213
+ else if (!ai->ai_next)
214
+ return rc;
215
+ }
216
+
217
+ return TRILOGY_ERR;
218
+ }
219
+
220
+ static char *strdupnullok(const char *str)
221
+ {
222
+ if (str == NULL) {
223
+ return NULL;
224
+ }
225
+ return strdup(str);
226
+ }
227
+
228
+ trilogy_sock_t *trilogy_sock_new(const trilogy_sockopt_t *opts)
229
+ {
230
+ struct trilogy_sock *sock = malloc(sizeof(struct trilogy_sock));
231
+
232
+ sock->base.connect_cb = _cb_raw_connect;
233
+ sock->base.read_cb = _cb_raw_read;
234
+ sock->base.write_cb = _cb_raw_write;
235
+ sock->base.wait_cb = _cb_wait;
236
+ sock->base.shutdown_cb = _cb_raw_shutdown;
237
+ sock->base.close_cb = _cb_raw_close;
238
+ sock->base.fd_cb = _cb_raw_fd;
239
+ sock->base.opts = *opts;
240
+
241
+ sock->base.opts.hostname = strdupnullok(opts->hostname);
242
+ sock->base.opts.path = strdupnullok(opts->path);
243
+ sock->base.opts.database = strdupnullok(opts->database);
244
+ sock->base.opts.username = strdupnullok(opts->username);
245
+
246
+ if (sock->base.opts.password) {
247
+ sock->base.opts.password = malloc(opts->password_len);
248
+ memcpy(sock->base.opts.password, opts->password, opts->password_len);
249
+ }
250
+
251
+ sock->base.opts.ssl_ca = strdupnullok(opts->ssl_ca);
252
+ sock->base.opts.ssl_capath = strdupnullok(opts->ssl_capath);
253
+ sock->base.opts.ssl_cert = strdupnullok(opts->ssl_cert);
254
+ sock->base.opts.ssl_cipher = strdupnullok(opts->ssl_cipher);
255
+ sock->base.opts.ssl_crl = strdupnullok(opts->ssl_crl);
256
+ sock->base.opts.ssl_crlpath = strdupnullok(opts->ssl_crlpath);
257
+ sock->base.opts.ssl_key = strdupnullok(opts->ssl_key);
258
+ sock->base.opts.tls_ciphersuites = strdupnullok(opts->tls_ciphersuites);
259
+
260
+ sock->fd = -1;
261
+ sock->addr = NULL;
262
+ sock->ssl = NULL;
263
+
264
+ return (trilogy_sock_t *)sock;
265
+ }
266
+
267
+ int trilogy_sock_resolve(trilogy_sock_t *_sock)
268
+ {
269
+ struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
270
+
271
+ if (sock->base.opts.hostname != NULL) {
272
+ struct addrinfo hint = {.ai_family = PF_UNSPEC, .ai_socktype = SOCK_STREAM};
273
+
274
+ char port[6];
275
+ snprintf(port, sizeof(port), "%hu", sock->base.opts.port);
276
+
277
+ if (getaddrinfo(sock->base.opts.hostname, port, &hint, &sock->addr) != 0) {
278
+ return TRILOGY_DNS_ERR;
279
+ }
280
+ } else if (sock->base.opts.path != NULL) {
281
+ struct sockaddr_un *sa;
282
+
283
+ if (strlen(sock->base.opts.path) + 1 > sizeof(sa->sun_path)) {
284
+ goto fail;
285
+ }
286
+
287
+ sa = calloc(1, sizeof(struct sockaddr_un));
288
+ sa->sun_family = AF_UNIX;
289
+ strcpy(sa->sun_path, sock->base.opts.path);
290
+
291
+ sock->addr = calloc(1, sizeof(struct addrinfo));
292
+ sock->addr->ai_family = PF_UNIX;
293
+ sock->addr->ai_socktype = SOCK_STREAM;
294
+ sock->addr->ai_addr = (struct sockaddr *)sa;
295
+ sock->addr->ai_addrlen = sizeof(struct sockaddr_un);
296
+ } else {
297
+ goto fail;
298
+ }
299
+
300
+ return TRILOGY_OK;
301
+
302
+ fail:
303
+ _cb_raw_close(_sock);
304
+ return TRILOGY_ERR;
305
+ }
306
+
307
+ static ssize_t ssl_io_return(struct trilogy_sock *sock, ssize_t ret)
308
+ {
309
+ if (ret < 0) {
310
+ int rc = SSL_get_error(sock->ssl, (int)ret);
311
+ if (rc == SSL_ERROR_WANT_WRITE || rc == SSL_ERROR_WANT_READ) {
312
+ return (ssize_t)TRILOGY_AGAIN;
313
+ } else if (rc == SSL_ERROR_SYSCALL && errno != 0) {
314
+ return (ssize_t)TRILOGY_SYSERR;
315
+ }
316
+ return (ssize_t)TRILOGY_OPENSSL_ERR;
317
+ }
318
+ return ret;
319
+ }
320
+
321
+ static ssize_t _cb_ssl_read(trilogy_sock_t *_sock, void *buf, size_t nread)
322
+ {
323
+ struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
324
+ ssize_t data_read = (ssize_t)SSL_read(sock->ssl, buf, (int)nread);
325
+ return ssl_io_return(sock, data_read);
326
+ }
327
+
328
+ static ssize_t _cb_ssl_write(trilogy_sock_t *_sock, const void *buf, size_t nwrite)
329
+ {
330
+ struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
331
+ ssize_t data_written = (ssize_t)SSL_write(sock->ssl, buf, (int)nwrite);
332
+ return ssl_io_return(sock, data_written);
333
+ }
334
+
335
+ static int _cb_ssl_shutdown(trilogy_sock_t *_sock)
336
+ {
337
+ struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
338
+
339
+ // If we have an SSL socket, it's invalid here and
340
+ // we need to close it. The OpenSSL explicitly states
341
+ // not to call SSL_shutdown on a broken SSL socket.
342
+ SSL_free(sock->ssl);
343
+ // Reset the handlers since we tore down SSL, so we
344
+ // fall back to the regular methods for detecting
345
+ // we have a closed connection and for the cleanup.
346
+ sock->base.read_cb = _cb_raw_read;
347
+ sock->base.write_cb = _cb_raw_write;
348
+ sock->base.shutdown_cb = _cb_raw_shutdown;
349
+ sock->base.close_cb = _cb_raw_close;
350
+ sock->ssl = NULL;
351
+
352
+ return _cb_raw_shutdown(_sock);
353
+ }
354
+
355
+ static int _cb_ssl_close(trilogy_sock_t *_sock)
356
+ {
357
+ struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
358
+ if (sock->ssl != NULL) {
359
+ SSL_shutdown(sock->ssl);
360
+ SSL_free(sock->ssl);
361
+ sock->ssl = NULL;
362
+ }
363
+ return _cb_raw_close(_sock);
364
+ }
365
+
366
+ #if OPENSSL_VERSION_NUMBER >= 0x1010000fL
367
+
368
+ static int trilogy_tls_version_map[] = {0, TLS1_VERSION, TLS1_1_VERSION, TLS1_2_VERSION
369
+ #ifdef TLS1_3_VERSION
370
+ ,
371
+ TLS1_3_VERSION
372
+ #else
373
+ ,
374
+ 0
375
+ #endif
376
+ };
377
+
378
+ long trilogy_set_min_proto_version(SSL_CTX *ctx, trilogy_tls_version_t version)
379
+ {
380
+ int ssl_ver = trilogy_tls_version_map[version];
381
+ if (ssl_ver == 0) {
382
+ ERR_put_error(ERR_LIB_SSL, SSL_F_SSL_CTX_SET_SSL_VERSION, SSL_R_UNSUPPORTED_PROTOCOL, NULL, 0);
383
+ return 0;
384
+ }
385
+ return SSL_CTX_set_min_proto_version(ctx, ssl_ver);
386
+ }
387
+
388
+ long trilogy_set_max_proto_version(SSL_CTX *ctx, trilogy_tls_version_t version)
389
+ {
390
+ int ssl_ver = trilogy_tls_version_map[version];
391
+ if (ssl_ver == 0) {
392
+ ERR_put_error(ERR_LIB_SSL, SSL_F_SSL_CTX_SET_SSL_VERSION, SSL_R_UNSUPPORTED_PROTOCOL, NULL, 0);
393
+ return 0;
394
+ }
395
+ return SSL_CTX_set_max_proto_version(ctx, ssl_ver);
396
+ }
397
+ #else
398
+
399
+ int trilogy_set_min_proto_version(SSL_CTX *ctx, trilogy_tls_version_t version)
400
+ {
401
+ long opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
402
+ switch (version) {
403
+ case TRILOGY_TLS_VERSION_13:
404
+ opts |= SSL_OP_NO_TLSv1_2;
405
+ case TRILOGY_TLS_VERSION_12:
406
+ opts |= SSL_OP_NO_TLSv1_1;
407
+ case TRILOGY_TLS_VERSION_11:
408
+ opts |= SSL_OP_NO_TLSv1;
409
+ default:
410
+ break;
411
+ }
412
+ // No need to handle 1.3 here since OpenSSL < 1.1.0 doesn't support that
413
+ // anyway
414
+ SSL_CTX_set_options(ctx, opts);
415
+ return 1;
416
+ }
417
+
418
+ int trilogy_set_max_proto_version(SSL_CTX *ctx, trilogy_tls_version_t version)
419
+ {
420
+ long opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
421
+ switch (version) {
422
+ case TRILOGY_TLS_VERSION_10:
423
+ opts |= SSL_OP_NO_TLSv1_1;
424
+ case TRILOGY_TLS_VERSION_11:
425
+ opts |= SSL_OP_NO_TLSv1_2;
426
+ default:
427
+ break;
428
+ }
429
+ SSL_CTX_set_options(ctx, opts);
430
+ return 1;
431
+ }
432
+ #endif
433
+
434
+ static SSL_CTX *trilogy_ssl_ctx(const trilogy_sockopt_t *opts)
435
+ {
436
+ SSL_CTX *ssl_ctx = SSL_CTX_new(SSLv23_client_method());
437
+
438
+ // Now handle all the custom options that we're given.
439
+ if (opts->tls_min_version != TRILOGY_TLS_VERSION_UNDEF) {
440
+ if (!trilogy_set_min_proto_version(ssl_ctx, opts->tls_min_version)) {
441
+ goto fail;
442
+ }
443
+ } else {
444
+ if (!trilogy_set_min_proto_version(ssl_ctx, TRILOGY_TLS_VERSION_12)) {
445
+ goto fail;
446
+ }
447
+ }
448
+
449
+ if (opts->tls_max_version != TRILOGY_TLS_VERSION_UNDEF) {
450
+ if (!trilogy_set_max_proto_version(ssl_ctx, opts->tls_max_version)) {
451
+ goto fail;
452
+ }
453
+ }
454
+
455
+ if (opts->ssl_cipher) {
456
+ if (!SSL_CTX_set_cipher_list(ssl_ctx, opts->ssl_cipher)) {
457
+ goto fail;
458
+ }
459
+ } else {
460
+ // Use a secure cipher list, based on TLS 1.2 and with authenticated
461
+ // encryption.
462
+ if (!SSL_CTX_set_cipher_list(ssl_ctx, "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:"
463
+ "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:"
464
+ "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305")) {
465
+ goto fail;
466
+ }
467
+ }
468
+
469
+ #if OPENSSL_VERSION_NUMBER >= 0x1010100fL
470
+ if (opts->tls_ciphersuites) {
471
+ if (!SSL_CTX_set_ciphersuites(ssl_ctx, opts->tls_ciphersuites)) {
472
+ goto fail;
473
+ }
474
+ }
475
+ #endif
476
+
477
+ switch (opts->ssl_mode) {
478
+ case TRILOGY_SSL_DISABLED:
479
+ break;
480
+ case TRILOGY_SSL_VERIFY_IDENTITY:
481
+ case TRILOGY_SSL_VERIFY_CA:
482
+ SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
483
+ break;
484
+ case TRILOGY_SSL_REQUIRED_NOVERIFY:
485
+ case TRILOGY_SSL_PREFERRED_NOVERIFY:
486
+ SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, NULL);
487
+ break;
488
+ }
489
+
490
+ if (opts->ssl_ca || opts->ssl_capath) {
491
+ if (!SSL_CTX_load_verify_locations(ssl_ctx, opts->ssl_ca, opts->ssl_capath)) {
492
+ goto fail;
493
+ }
494
+ } else {
495
+ // Use the default systems paths to verify the certificate
496
+ if (!SSL_CTX_set_default_verify_paths(ssl_ctx)) {
497
+ goto fail;
498
+ }
499
+ }
500
+
501
+ if (opts->ssl_cert || opts->ssl_key) {
502
+ if (opts->ssl_key) {
503
+ if (!SSL_CTX_use_PrivateKey_file(ssl_ctx, opts->ssl_key, SSL_FILETYPE_PEM)) {
504
+ goto fail;
505
+ }
506
+ }
507
+ if (opts->ssl_cert) {
508
+ if (!SSL_CTX_use_certificate_chain_file(ssl_ctx, opts->ssl_cert)) {
509
+ goto fail;
510
+ }
511
+ }
512
+
513
+ if (!SSL_CTX_check_private_key(ssl_ctx)) {
514
+ goto fail;
515
+ }
516
+ }
517
+
518
+ if (opts->ssl_crl || opts->ssl_crlpath) {
519
+ X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx);
520
+
521
+ if (!X509_STORE_load_locations(store, opts->ssl_crl, opts->ssl_crlpath)) {
522
+ goto fail;
523
+ }
524
+
525
+ if (!X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL)) {
526
+ goto fail;
527
+ }
528
+ }
529
+ return ssl_ctx;
530
+
531
+ fail:
532
+ SSL_CTX_free(ssl_ctx);
533
+ return NULL;
534
+ }
535
+
536
+ int trilogy_sock_upgrade_ssl(trilogy_sock_t *_sock)
537
+ {
538
+ struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
539
+
540
+ SSL_CTX *ctx = trilogy_ssl_ctx(&sock->base.opts);
541
+
542
+ if (!ctx) {
543
+ return TRILOGY_OPENSSL_ERR;
544
+ }
545
+
546
+ sock->ssl = SSL_new(ctx);
547
+ SSL_CTX_free(ctx);
548
+
549
+ if (sock->base.opts.ssl_mode == TRILOGY_SSL_VERIFY_IDENTITY && sock->base.opts.hostname == NULL) {
550
+ // If hostname validation is requested and no hostname provided, treat it as an error.
551
+ #if OPENSSL_VERSION_NUMBER >= 0x1010000fL
552
+ ERR_put_error(ERR_LIB_SSL, SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, SSL_R_CERTIFICATE_VERIFY_FAILED, NULL, 0);
553
+ #else
554
+ ERR_put_error(ERR_LIB_SSL, SSL_F_SSL3_GET_SERVER_CERTIFICATE, SSL_R_CERTIFICATE_VERIFY_FAILED, NULL, 0);
555
+ #endif
556
+ goto fail;
557
+ }
558
+
559
+ // Set the SNI hostname for the connection
560
+ if (sock->base.opts.hostname != NULL) {
561
+ if (!SSL_set_tlsext_host_name(sock->ssl, sock->base.opts.hostname)) {
562
+ goto fail;
563
+ }
564
+ }
565
+
566
+ // Newer API available since 1.0.2, so we don't have to do manual work.
567
+ #if OPENSSL_VERSION_NUMBER >= 0x1000200fL
568
+ if (sock->base.opts.ssl_mode == TRILOGY_SSL_VERIFY_IDENTITY) {
569
+ X509_VERIFY_PARAM *param = SSL_get0_param(sock->ssl);
570
+ const char *hostname = sock->base.opts.hostname;
571
+ X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
572
+ if (!X509_VERIFY_PARAM_set1_host(param, hostname, strlen(hostname))) {
573
+ goto fail;
574
+ }
575
+ }
576
+ #endif
577
+
578
+ if (!SSL_set_fd(sock->ssl, sock->fd))
579
+ goto fail;
580
+
581
+ for (;;) {
582
+ int ret = SSL_connect(sock->ssl);
583
+ if (ret == 1) {
584
+ #if OPENSSL_VERSION_NUMBER < 0x1000200fL
585
+ if (sock->base.opts.ssl_mode == TRILOGY_SSL_VERIFY_IDENTITY) {
586
+ if (validate_hostname(sock->base.opts.hostname, SSL_get_peer_certificate(sock->ssl)) != MatchFound) {
587
+ // Fake the error message to be the same as it would be on 1.0.2 and newer.
588
+ ERR_put_error(ERR_LIB_SSL, SSL_F_SSL3_GET_SERVER_CERTIFICATE, SSL_R_CERTIFICATE_VERIFY_FAILED, NULL,
589
+ 0);
590
+ goto fail;
591
+ }
592
+ }
593
+ #endif
594
+ break;
595
+ }
596
+
597
+ switch (SSL_get_error(sock->ssl, ret)) {
598
+ case SSL_ERROR_WANT_READ:
599
+ if (trilogy_sock_wait_read(_sock) < 0)
600
+ goto fail;
601
+ break;
602
+
603
+ case SSL_ERROR_WANT_WRITE:
604
+ if (trilogy_sock_wait_write(_sock) < 0)
605
+ goto fail;
606
+ break;
607
+
608
+ default:
609
+ goto fail;
610
+ }
611
+ }
612
+
613
+ sock->base.read_cb = _cb_ssl_read;
614
+ sock->base.write_cb = _cb_ssl_write;
615
+ sock->base.shutdown_cb = _cb_ssl_shutdown;
616
+ sock->base.close_cb = _cb_ssl_close;
617
+ return TRILOGY_OK;
618
+
619
+ fail:
620
+ SSL_free(sock->ssl);
621
+ sock->ssl = NULL;
622
+ return TRILOGY_OPENSSL_ERR;
623
+ }