1 /*
2 * Copyright 2016 MongoDB, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "mongoc-config.h"
18
19 #ifdef MONGOC_ENABLE_SSL_OPENSSL
20
21 #include <bson/bson.h>
22
23 #include <errno.h>
24 #include <string.h>
25 #include <openssl/bio.h>
26 #include <openssl/ssl.h>
27 #include <openssl/err.h>
28 #include <openssl/x509v3.h>
29
30 #include "mongoc-counters-private.h"
31 #include "mongoc-errno-private.h"
32 #include "mongoc-ssl.h"
33 #include "mongoc-ssl-private.h"
34 #include "mongoc-stream-tls.h"
35 #include "mongoc-stream-private.h"
36 #include "mongoc-stream-tls-private.h"
37 #include "mongoc-stream-tls-openssl-bio-private.h"
38 #include "mongoc-stream-tls-openssl-private.h"
39 #include "mongoc-openssl-private.h"
40 #include "mongoc-trace-private.h"
41 #include "mongoc-log.h"
42 #include "mongoc-error.h"
43
44
45 #undef MONGOC_LOG_DOMAIN
46 #define MONGOC_LOG_DOMAIN "stream-tls-openssl"
47
48 #define MONGOC_STREAM_TLS_OPENSSL_BUFFER_SIZE 4096
49
50 #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
51 (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
52 static void
BIO_meth_free(BIO_METHOD * meth)53 BIO_meth_free (BIO_METHOD *meth)
54 {
55 /* Nothing to free pre OpenSSL 1.1.0 */
56 }
57 #endif
58
59
60 /*
61 *--------------------------------------------------------------------------
62 *
63 * _mongoc_stream_tls_openssl_destroy --
64 *
65 * Cleanup after usage of a mongoc_stream_tls_openssl_t. Free all
66 *allocated
67 * resources and ensure connections are closed.
68 *
69 * Returns:
70 * None.
71 *
72 * Side effects:
73 * None.
74 *
75 *--------------------------------------------------------------------------
76 */
77
78 static void
_mongoc_stream_tls_openssl_destroy(mongoc_stream_t * stream)79 _mongoc_stream_tls_openssl_destroy (mongoc_stream_t *stream)
80 {
81 mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream;
82 mongoc_stream_tls_openssl_t *openssl =
83 (mongoc_stream_tls_openssl_t *) tls->ctx;
84
85 BSON_ASSERT (tls);
86
87 BIO_free_all (openssl->bio);
88 openssl->bio = NULL;
89
90 BIO_meth_free (openssl->meth);
91 openssl->meth = NULL;
92
93 mongoc_stream_destroy (tls->base_stream);
94 tls->base_stream = NULL;
95
96 SSL_CTX_free (openssl->ctx);
97 openssl->ctx = NULL;
98
99 mongoc_openssl_ocsp_opt_destroy (openssl->ocsp_opts);
100 openssl->ocsp_opts = NULL;
101
102 bson_free (openssl);
103 bson_free (stream);
104
105 mongoc_counter_streams_active_dec ();
106 mongoc_counter_streams_disposed_inc ();
107 }
108
109
110 /*
111 *--------------------------------------------------------------------------
112 *
113 * _mongoc_stream_tls_openssl_failed --
114 *
115 * Called on stream failure. Same as _mongoc_stream_tls_openssl_destroy()
116 *
117 * Returns:
118 * None.
119 *
120 * Side effects:
121 * None.
122 *
123 *--------------------------------------------------------------------------
124 */
125
126 static void
_mongoc_stream_tls_openssl_failed(mongoc_stream_t * stream)127 _mongoc_stream_tls_openssl_failed (mongoc_stream_t *stream)
128 {
129 _mongoc_stream_tls_openssl_destroy (stream);
130 }
131
132
133 /*
134 *--------------------------------------------------------------------------
135 *
136 * _mongoc_stream_tls_openssl_close --
137 *
138 * Close the underlying socket.
139 *
140 * Linus dictates that you should not check the result of close()
141 * since there is a race condition with EAGAIN and a new file
142 * descriptor being opened.
143 *
144 * Returns:
145 * 0 on success; otherwise -1.
146 *
147 * Side effects:
148 * The BIO fd is closed.
149 *
150 *--------------------------------------------------------------------------
151 */
152
153 static int
_mongoc_stream_tls_openssl_close(mongoc_stream_t * stream)154 _mongoc_stream_tls_openssl_close (mongoc_stream_t *stream)
155 {
156 mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream;
157 int ret = 0;
158 ENTRY;
159
160 BSON_ASSERT (tls);
161
162 ret = mongoc_stream_close (tls->base_stream);
163 RETURN (ret);
164 }
165
166
167 /*
168 *--------------------------------------------------------------------------
169 *
170 * _mongoc_stream_tls_openssl_flush --
171 *
172 * Flush the underlying stream.
173 *
174 * Returns:
175 * 0 if successful; otherwise -1.
176 *
177 * Side effects:
178 * None.
179 *
180 *--------------------------------------------------------------------------
181 */
182
183 static int
_mongoc_stream_tls_openssl_flush(mongoc_stream_t * stream)184 _mongoc_stream_tls_openssl_flush (mongoc_stream_t *stream)
185 {
186 mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream;
187 mongoc_stream_tls_openssl_t *openssl =
188 (mongoc_stream_tls_openssl_t *) tls->ctx;
189
190 BSON_ASSERT (openssl);
191
192 return BIO_flush (openssl->bio);
193 }
194
195
196 static ssize_t
_mongoc_stream_tls_openssl_write(mongoc_stream_tls_t * tls,char * buf,size_t buf_len)197 _mongoc_stream_tls_openssl_write (mongoc_stream_tls_t *tls,
198 char *buf,
199 size_t buf_len)
200 {
201 mongoc_stream_tls_openssl_t *openssl =
202 (mongoc_stream_tls_openssl_t *) tls->ctx;
203 ssize_t ret;
204 int64_t now;
205 int64_t expire = 0;
206 ENTRY;
207
208 BSON_ASSERT (tls);
209 BSON_ASSERT (buf);
210 BSON_ASSERT (buf_len);
211
212 if (tls->timeout_msec >= 0) {
213 expire = bson_get_monotonic_time () + (tls->timeout_msec * 1000UL);
214 }
215
216 ret = BIO_write (openssl->bio, buf, buf_len);
217
218 if (ret <= 0) {
219 return ret;
220 }
221
222 if (expire) {
223 now = bson_get_monotonic_time ();
224
225 if ((expire - now) < 0) {
226 if (ret < buf_len) {
227 mongoc_counter_streams_timeout_inc ();
228 }
229
230 tls->timeout_msec = 0;
231 } else {
232 tls->timeout_msec = (expire - now) / 1000L;
233 }
234 }
235
236 RETURN (ret);
237 }
238
239
240 /*
241 *--------------------------------------------------------------------------
242 *
243 * _mongoc_stream_tls_openssl_writev --
244 *
245 * Write the iovec to the stream. This function will try to write
246 * all of the bytes or fail. If the number of bytes is not equal
247 * to the number requested, a failure or EOF has occurred.
248 *
249 * Returns:
250 * -1 on failure, otherwise the number of bytes written.
251 *
252 * Side effects:
253 * None.
254 *
255 * This function is copied as _mongoc_stream_tls_secure_transport_writev
256 *--------------------------------------------------------------------------
257 */
258
259 static ssize_t
_mongoc_stream_tls_openssl_writev(mongoc_stream_t * stream,mongoc_iovec_t * iov,size_t iovcnt,int32_t timeout_msec)260 _mongoc_stream_tls_openssl_writev (mongoc_stream_t *stream,
261 mongoc_iovec_t *iov,
262 size_t iovcnt,
263 int32_t timeout_msec)
264 {
265 mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream;
266 char buf[MONGOC_STREAM_TLS_OPENSSL_BUFFER_SIZE];
267 ssize_t ret = 0;
268 ssize_t child_ret;
269 size_t i;
270 size_t iov_pos = 0;
271
272 /* There's a bit of a dance to coalesce vectorized writes into
273 * MONGOC_STREAM_TLS_OPENSSL_BUFFER_SIZE'd writes to avoid lots of small tls
274 * packets.
275 *
276 * The basic idea is that we want to combine writes in the buffer if they're
277 * smaller than the buffer, flushing as it gets full. For larger writes, or
278 * the last write in the iovec array, we want to ignore the buffer and just
279 * write immediately. We take care of doing buffer writes by re-invoking
280 * ourself with a single iovec_t, pointing at our stack buffer.
281 */
282 char *buf_head = buf;
283 char *buf_tail = buf;
284 char *buf_end = buf + MONGOC_STREAM_TLS_OPENSSL_BUFFER_SIZE;
285 size_t bytes;
286
287 char *to_write = NULL;
288 size_t to_write_len;
289
290 BSON_ASSERT (tls);
291 BSON_ASSERT (iov);
292 BSON_ASSERT (iovcnt);
293 ENTRY;
294
295 tls->timeout_msec = timeout_msec;
296
297 for (i = 0; i < iovcnt; i++) {
298 iov_pos = 0;
299
300 while (iov_pos < iov[i].iov_len) {
301 if (buf_head != buf_tail ||
302 ((i + 1 < iovcnt) &&
303 ((buf_end - buf_tail) > (iov[i].iov_len - iov_pos)))) {
304 /* If we have either of:
305 * - buffered bytes already
306 * - another iovec to send after this one and we don't have more
307 * bytes to send than the size of the buffer.
308 *
309 * copy into the buffer */
310
311 bytes = BSON_MIN (iov[i].iov_len - iov_pos, buf_end - buf_tail);
312
313 memcpy (buf_tail, (char *) iov[i].iov_base + iov_pos, bytes);
314 buf_tail += bytes;
315 iov_pos += bytes;
316
317 if (buf_tail == buf_end) {
318 /* If we're full, request send */
319
320 to_write = buf_head;
321 to_write_len = buf_tail - buf_head;
322
323 buf_tail = buf_head = buf;
324 }
325 } else {
326 /* Didn't buffer, so just write it through */
327
328 to_write = (char *) iov[i].iov_base + iov_pos;
329 to_write_len = iov[i].iov_len - iov_pos;
330
331 iov_pos += to_write_len;
332 }
333
334 if (to_write) {
335 /* We get here if we buffered some bytes and filled the buffer, or
336 * if we didn't buffer and have to send out of the iovec */
337
338 child_ret =
339 _mongoc_stream_tls_openssl_write (tls, to_write, to_write_len);
340 if (child_ret != to_write_len) {
341 TRACE ("Got child_ret: %ld while to_write_len is: %ld",
342 child_ret,
343 to_write_len);
344 }
345
346 if (child_ret < 0) {
347 TRACE ("Returning what I had (%ld) as apposed to the error "
348 "(%ld, errno:%d)",
349 ret,
350 child_ret,
351 errno);
352 RETURN (ret);
353 }
354
355 ret += child_ret;
356
357 if (child_ret < to_write_len) {
358 /* we timed out, so send back what we could send */
359
360 RETURN (ret);
361 }
362
363 to_write = NULL;
364 }
365 }
366 }
367
368 if (buf_head != buf_tail) {
369 /* If we have any bytes buffered, send */
370
371 child_ret =
372 _mongoc_stream_tls_openssl_write (tls, buf_head, buf_tail - buf_head);
373
374 if (child_ret < 0) {
375 RETURN (child_ret);
376 }
377
378 ret += child_ret;
379 }
380
381 if (ret >= 0) {
382 mongoc_counter_streams_egress_add (ret);
383 }
384
385 RETURN (ret);
386 }
387
388
389 /*
390 *--------------------------------------------------------------------------
391 *
392 * _mongoc_stream_tls_openssl_readv --
393 *
394 * Read from the stream into iov. This function will try to read
395 * all of the bytes or fail. If the number of bytes is not equal
396 * to the number requested, a failure or EOF has occurred.
397 *
398 * Returns:
399 * -1 on failure, 0 on EOF, otherwise the number of bytes read.
400 *
401 * Side effects:
402 * iov buffers will be written to.
403 *
404 * This function is copied as _mongoc_stream_tls_secure_transport_readv
405 *
406 *--------------------------------------------------------------------------
407 */
408
409 static ssize_t
_mongoc_stream_tls_openssl_readv(mongoc_stream_t * stream,mongoc_iovec_t * iov,size_t iovcnt,size_t min_bytes,int32_t timeout_msec)410 _mongoc_stream_tls_openssl_readv (mongoc_stream_t *stream,
411 mongoc_iovec_t *iov,
412 size_t iovcnt,
413 size_t min_bytes,
414 int32_t timeout_msec)
415 {
416 mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream;
417 mongoc_stream_tls_openssl_t *openssl =
418 (mongoc_stream_tls_openssl_t *) tls->ctx;
419 ssize_t ret = 0;
420 size_t i;
421 int read_ret;
422 size_t iov_pos = 0;
423 int64_t now;
424 int64_t expire = 0;
425 ENTRY;
426
427 BSON_ASSERT (tls);
428 BSON_ASSERT (iov);
429 BSON_ASSERT (iovcnt);
430
431 tls->timeout_msec = timeout_msec;
432
433 if (timeout_msec >= 0) {
434 expire = bson_get_monotonic_time () + (timeout_msec * 1000UL);
435 }
436
437 for (i = 0; i < iovcnt; i++) {
438 iov_pos = 0;
439
440 while (iov_pos < iov[i].iov_len) {
441 read_ret = BIO_read (openssl->bio,
442 (char *) iov[i].iov_base + iov_pos,
443 (int) (iov[i].iov_len - iov_pos));
444
445 /* https://www.openssl.org/docs/crypto/BIO_should_retry.html:
446 *
447 * If BIO_should_retry() returns false then the precise "error
448 * condition" depends on the BIO type that caused it and the return
449 * code of the BIO operation. For example if a call to BIO_read() on a
450 * socket BIO returns 0 and BIO_should_retry() is false then the cause
451 * will be that the connection closed.
452 */
453 if (read_ret < 0 ||
454 (read_ret == 0 && !BIO_should_retry (openssl->bio))) {
455 return -1;
456 }
457
458 if (expire) {
459 now = bson_get_monotonic_time ();
460
461 if ((expire - now) < 0) {
462 if (read_ret == 0) {
463 mongoc_counter_streams_timeout_inc ();
464 #ifdef _WIN32
465 errno = WSAETIMEDOUT;
466 #else
467 errno = ETIMEDOUT;
468 #endif
469 RETURN (-1);
470 }
471
472 tls->timeout_msec = 0;
473 } else {
474 tls->timeout_msec = (expire - now) / 1000L;
475 }
476 }
477
478 ret += read_ret;
479
480 if ((size_t) ret >= min_bytes) {
481 mongoc_counter_streams_ingress_add (ret);
482 RETURN (ret);
483 }
484
485 iov_pos += read_ret;
486 }
487 }
488
489 if (ret >= 0) {
490 mongoc_counter_streams_ingress_add (ret);
491 }
492
493 RETURN (ret);
494 }
495
496
497 /*
498 *--------------------------------------------------------------------------
499 *
500 * _mongoc_stream_tls_openssl_setsockopt --
501 *
502 * Perform a setsockopt on the underlying stream.
503 *
504 * Returns:
505 * -1 on failure, otherwise opt specific value.
506 *
507 * Side effects:
508 * None.
509 *
510 *--------------------------------------------------------------------------
511 */
512
513 static int
_mongoc_stream_tls_openssl_setsockopt(mongoc_stream_t * stream,int level,int optname,void * optval,mongoc_socklen_t optlen)514 _mongoc_stream_tls_openssl_setsockopt (mongoc_stream_t *stream,
515 int level,
516 int optname,
517 void *optval,
518 mongoc_socklen_t optlen)
519 {
520 mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream;
521
522 BSON_ASSERT (tls);
523
524 return mongoc_stream_setsockopt (
525 tls->base_stream, level, optname, optval, optlen);
526 }
527
528
529 static mongoc_stream_t *
_mongoc_stream_tls_openssl_get_base_stream(mongoc_stream_t * stream)530 _mongoc_stream_tls_openssl_get_base_stream (mongoc_stream_t *stream)
531 {
532 mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream;
533 return tls->base_stream;
534 }
535
536
537 static bool
_mongoc_stream_tls_openssl_check_closed(mongoc_stream_t * stream)538 _mongoc_stream_tls_openssl_check_closed (mongoc_stream_t *stream) /* IN */
539 {
540 mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream;
541 BSON_ASSERT (stream);
542 return mongoc_stream_check_closed (tls->base_stream);
543 }
544
545
546 /**
547 * mongoc_stream_tls_openssl_handshake:
548 */
549 static bool
_mongoc_stream_tls_openssl_handshake(mongoc_stream_t * stream,const char * host,int * events,bson_error_t * error)550 _mongoc_stream_tls_openssl_handshake (mongoc_stream_t *stream,
551 const char *host,
552 int *events,
553 bson_error_t *error)
554 {
555 mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream;
556 mongoc_stream_tls_openssl_t *openssl =
557 (mongoc_stream_tls_openssl_t *) tls->ctx;
558 SSL *ssl;
559
560 BSON_ASSERT (tls);
561 BSON_ASSERT (host);
562 ENTRY;
563
564 BIO_get_ssl (openssl->bio, &ssl);
565
566 if (BIO_do_handshake (openssl->bio) == 1) {
567 *events = 0;
568
569 #ifdef MONGOC_ENABLE_OCSP_OPENSSL
570 /* Validate OCSP */
571 if (openssl->ocsp_opts &&
572 1 != _mongoc_ocsp_tlsext_status (ssl, openssl->ocsp_opts)) {
573 bson_set_error (error,
574 MONGOC_ERROR_STREAM,
575 MONGOC_ERROR_STREAM_SOCKET,
576 "TLS handshake failed: Failed OCSP verification");
577 RETURN (false);
578 }
579 #endif
580
581 if (_mongoc_openssl_check_peer_hostname (
582 ssl, host, tls->ssl_opts.allow_invalid_hostname)) {
583 RETURN (true);
584 }
585
586 bson_set_error (error,
587 MONGOC_ERROR_STREAM,
588 MONGOC_ERROR_STREAM_SOCKET,
589 "TLS handshake failed: Failed certificate verification");
590
591 RETURN (false);
592 }
593
594 if (BIO_should_retry (openssl->bio)) {
595 *events = BIO_should_read (openssl->bio) ? POLLIN : POLLOUT;
596 RETURN (false);
597 }
598
599 if (!errno) {
600 #ifdef _WIN32
601 errno = WSAETIMEDOUT;
602 #else
603 errno = ETIMEDOUT;
604 #endif
605 }
606
607
608 *events = 0;
609 bson_set_error (error,
610 MONGOC_ERROR_STREAM,
611 MONGOC_ERROR_STREAM_SOCKET,
612 "TLS handshake failed: %s",
613 ERR_error_string (ERR_get_error (), NULL));
614
615 RETURN (false);
616 }
617
618 /* Callback to get the client provided SNI, if any
619 * It is only called in SSL "server mode" (e.g. when using the Mock Server),
620 * and we don't actually use the hostname for anything, just debug print it
621 */
622 static int
_mongoc_stream_tls_openssl_sni(SSL * ssl,int * ad,void * arg)623 _mongoc_stream_tls_openssl_sni (SSL *ssl, int *ad, void *arg)
624 {
625 const char *hostname;
626
627 if (ssl == NULL) {
628 TRACE ("%s", "No SNI hostname provided");
629 return SSL_TLSEXT_ERR_NOACK;
630 }
631
632 hostname = SSL_get_servername (ssl, TLSEXT_NAMETYPE_host_name);
633 /* This is intentionally debug since its only used by the mock test server */
634 MONGOC_DEBUG ("Got SNI: '%s'", hostname);
635
636 return SSL_TLSEXT_ERR_OK;
637 }
638
639 static bool
_mongoc_stream_tls_openssl_timed_out(mongoc_stream_t * stream)640 _mongoc_stream_tls_openssl_timed_out (mongoc_stream_t *stream)
641 {
642 mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream;
643
644 ENTRY;
645
646 RETURN (mongoc_stream_timed_out (tls->base_stream));
647 }
648
649 static bool
_mongoc_stream_tls_openssl_should_retry(mongoc_stream_t * stream)650 _mongoc_stream_tls_openssl_should_retry (mongoc_stream_t *stream)
651 {
652 mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream;
653 mongoc_stream_tls_openssl_t *openssl =
654 (mongoc_stream_tls_openssl_t *) tls->ctx;
655
656 ENTRY;
657
658 if (BIO_should_retry (openssl->bio)) {
659 RETURN (true);
660 }
661
662 RETURN (mongoc_stream_should_retry (tls->base_stream));
663 }
664
665 /*
666 *--------------------------------------------------------------------------
667 *
668 * mongoc_stream_tls_openssl_new --
669 *
670 * Creates a new mongoc_stream_tls_openssl_t to communicate with a remote
671 * server using a TLS stream.
672 *
673 * @base_stream should be a stream that will become owned by the
674 * resulting tls stream. It will be used for raw I/O.
675 *
676 * @trust_store_dir should be a path to the SSL cert db to use for
677 * verifying trust of the remote server.
678 *
679 * Returns:
680 * NULL on failure, otherwise a mongoc_stream_t.
681 *
682 * Side effects:
683 * None.
684 *
685 *--------------------------------------------------------------------------
686 */
687
688 mongoc_stream_t *
mongoc_stream_tls_openssl_new(mongoc_stream_t * base_stream,const char * host,mongoc_ssl_opt_t * opt,int client)689 mongoc_stream_tls_openssl_new (mongoc_stream_t *base_stream,
690 const char *host,
691 mongoc_ssl_opt_t *opt,
692 int client)
693 {
694 mongoc_stream_tls_t *tls;
695 mongoc_stream_tls_openssl_t *openssl;
696 mongoc_openssl_ocsp_opt_t *ocsp_opts = NULL;
697 SSL_CTX *ssl_ctx = NULL;
698 BIO *bio_ssl = NULL;
699 BIO *bio_mongoc_shim = NULL;
700 BIO_METHOD *meth;
701
702 BSON_ASSERT (base_stream);
703 BSON_ASSERT (opt);
704 ENTRY;
705
706 ssl_ctx = _mongoc_openssl_ctx_new (opt);
707
708 if (!ssl_ctx) {
709 RETURN (NULL);
710 }
711
712 #if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
713 if (!opt->allow_invalid_hostname) {
714 struct in_addr addr;
715 struct in6_addr addr6;
716 X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_new ();
717
718 X509_VERIFY_PARAM_set_hostflags (param,
719 X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
720 if (inet_pton (AF_INET, host, &addr) ||
721 inet_pton (AF_INET6, host, &addr6)) {
722 X509_VERIFY_PARAM_set1_ip_asc (param, host);
723 } else {
724 X509_VERIFY_PARAM_set1_host (param, host, 0);
725 }
726 SSL_CTX_set1_param (ssl_ctx, param);
727 X509_VERIFY_PARAM_free (param);
728 }
729 #endif
730
731 if (!client) {
732 /* Only used by the Mock Server.
733 * Set a callback to get the SNI, if provided */
734 SSL_CTX_set_tlsext_servername_callback (ssl_ctx,
735 _mongoc_stream_tls_openssl_sni);
736 }
737
738 if (opt->weak_cert_validation) {
739 SSL_CTX_set_verify (ssl_ctx, SSL_VERIFY_NONE, NULL);
740 } else {
741 SSL_CTX_set_verify (ssl_ctx, SSL_VERIFY_PEER, NULL);
742 }
743
744 bio_ssl = BIO_new_ssl (ssl_ctx, client);
745 if (!bio_ssl) {
746 SSL_CTX_free (ssl_ctx);
747 RETURN (NULL);
748 }
749 meth = mongoc_stream_tls_openssl_bio_meth_new ();
750 bio_mongoc_shim = BIO_new (meth);
751 if (!bio_mongoc_shim) {
752 BIO_free_all (bio_ssl);
753 BIO_meth_free (meth);
754 SSL_CTX_free (ssl_ctx);
755 RETURN (NULL);
756 }
757
758 /* Added in OpenSSL 0.9.8f, as a build time option */
759 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
760 if (client) {
761 SSL *ssl;
762 /* Set the SNI hostname we are expecting certificate for */
763 BIO_get_ssl (bio_ssl, &ssl);
764 SSL_set_tlsext_host_name (ssl, host);
765 #endif
766 }
767
768 BIO_push (bio_ssl, bio_mongoc_shim);
769
770 #ifdef MONGOC_ENABLE_OCSP_OPENSSL
771 if (client && !opt->weak_cert_validation &&
772 !_mongoc_ssl_opts_disable_certificate_revocation_check (opt)) {
773 SSL *ssl;
774
775 BIO_get_ssl (bio_ssl, &ssl);
776
777 /* Set the status_request extension on the SSL object.
778 * Do not use SSL_CTX_set_tlsext_status_type, since that requires OpenSSL
779 * 1.1.0.
780 */
781 if (!SSL_set_tlsext_status_type (ssl, TLSEXT_STATUSTYPE_ocsp)) {
782 MONGOC_ERROR ("cannot enable OCSP status request extension");
783 mongoc_openssl_ocsp_opt_destroy (ocsp_opts);
784 BIO_free_all (bio_ssl);
785 BIO_meth_free (meth);
786 SSL_CTX_free (ssl_ctx);
787 RETURN (NULL);
788 }
789
790 ocsp_opts = bson_malloc0 (sizeof (mongoc_openssl_ocsp_opt_t));
791 ocsp_opts->allow_invalid_hostname = opt->allow_invalid_hostname;
792 ocsp_opts->weak_cert_validation = opt->weak_cert_validation;
793 ocsp_opts->disable_endpoint_check =
794 _mongoc_ssl_opts_disable_ocsp_endpoint_check (opt);
795 ocsp_opts->host = bson_strdup (host);
796 _mongoc_ssl_opts_copy_to (opt, &ocsp_opts->ssl_opts, true);
797 }
798 #endif /* MONGOC_ENABLE_OCSP_OPENSSL */
799
800 openssl = (mongoc_stream_tls_openssl_t *) bson_malloc0 (sizeof *openssl);
801 openssl->bio = bio_ssl;
802 openssl->meth = meth;
803 openssl->ctx = ssl_ctx;
804 openssl->ocsp_opts = ocsp_opts;
805
806 tls = (mongoc_stream_tls_t *) bson_malloc0 (sizeof *tls);
807 tls->parent.type = MONGOC_STREAM_TLS;
808 tls->parent.destroy = _mongoc_stream_tls_openssl_destroy;
809 tls->parent.failed = _mongoc_stream_tls_openssl_failed;
810 tls->parent.close = _mongoc_stream_tls_openssl_close;
811 tls->parent.flush = _mongoc_stream_tls_openssl_flush;
812 tls->parent.writev = _mongoc_stream_tls_openssl_writev;
813 tls->parent.readv = _mongoc_stream_tls_openssl_readv;
814 tls->parent.setsockopt = _mongoc_stream_tls_openssl_setsockopt;
815 tls->parent.get_base_stream = _mongoc_stream_tls_openssl_get_base_stream;
816 tls->parent.check_closed = _mongoc_stream_tls_openssl_check_closed;
817 tls->parent.timed_out = _mongoc_stream_tls_openssl_timed_out;
818 tls->parent.should_retry = _mongoc_stream_tls_openssl_should_retry;
819 memcpy (&tls->ssl_opts, opt, sizeof tls->ssl_opts);
820 tls->handshake = _mongoc_stream_tls_openssl_handshake;
821 tls->ctx = (void *) openssl;
822 tls->timeout_msec = -1;
823 tls->base_stream = base_stream;
824 mongoc_stream_tls_openssl_bio_set_data (bio_mongoc_shim, tls);
825
826 mongoc_counter_streams_active_inc ();
827
828 RETURN ((mongoc_stream_t *) tls);
829 }
830
831 void
mongoc_openssl_ocsp_opt_destroy(void * ocsp_opt)832 mongoc_openssl_ocsp_opt_destroy (void *ocsp_opt)
833 {
834 mongoc_openssl_ocsp_opt_t *casted;
835
836 if (!ocsp_opt) {
837 return;
838 }
839 casted = (mongoc_openssl_ocsp_opt_t *) ocsp_opt;
840 bson_free (casted->host);
841 _mongoc_ssl_opts_cleanup (&casted->ssl_opts, true);
842 bson_free (ocsp_opt);
843 }
844
845 #endif /* MONGOC_ENABLE_SSL_OPENSSL */
846