Skip to content

Commit 1184f02

Browse files
committed
CDRIVER-3668 support OCSP back to OpenSSL 1.0.1 (#623)
- change SSL_CTX_set_tlsext_status_type to SSL_set_tlsext_status_type. - polyfill SSL_get0_verified_chain, NID_tlsfeature, and hostname check. - check for status_request from the tlsfeature extension when inspecting peer certificate. - skip time check for older OpenSSL when updating cache entries. - perform the OCSP check after the handshake, since sometimes the peer certificate is not available in the callback in OpenSSL <= 1.0.2. - check tlsDisableOCSPEndpointCheck before reaching out to a responder. - make tlsDisableOCSPEndpointCheck and tlsDisableCertificateRevocationCheck URI options implicitly enable TLS. - enable OCSP tests on OpenSSL and macOS that were skipped. - add OCSP tests for OpenSSL 1.0.1. - update OCSP OpenSSL documentation. - change OCSP verification logs from MONGOC_DEBUG to TRACE in successful cases.
1 parent 28cb13d commit 1184f02

15 files changed

+2141
-233
lines changed

.evergreen/config.yml

Lines changed: 1731 additions & 101 deletions
Large diffs are not rendered by default.

build/evergreen_config_lib/tasks.py

Lines changed: 40 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,15 @@
3131
class CompileTask(NamedTask):
3232
def __init__(self, task_name, tags=None, config='debug',
3333
compression='default', continue_on_err=False,
34-
extra_commands=None, depends_on=None,
35-
extra_script=None, **kwargs):
34+
suffix_commands=None, depends_on=None,
35+
extra_script=None, prefix_commands=None, **kwargs):
3636
super(CompileTask, self).__init__(task_name=task_name,
3737
depends_on=depends_on,
3838
tags=tags,
3939
**kwargs)
4040

41-
self.extra_commands = extra_commands or []
41+
self.suffix_commands = suffix_commands or []
42+
self.prefix_commands = prefix_commands or []
4243
if extra_script:
4344
self.extra_script = "\n" + extra_script
4445
else:
@@ -65,6 +66,8 @@ def __init__(self, task_name, tags=None, config='debug',
6566
def to_dict(self):
6667
task = super(CompileTask, self).to_dict()
6768

69+
task['commands'].extend(self.prefix_commands)
70+
6871
script = ''
6972
for opt, value in sorted(self.compile_sh_opt.items()):
7073
script += 'export %s="%s"\n' % (opt, value)
@@ -73,7 +76,7 @@ def to_dict(self):
7376
self.extra_script
7477
task['commands'].append(shell_mongoc(script))
7578
task['commands'].append(func('upload build'))
76-
task['commands'].extend(self.extra_commands)
79+
task['commands'].extend(self.suffix_commands)
7780
return task
7881

7982

@@ -135,7 +138,7 @@ def __init__(self, *args, **kwargs):
135138

136139

137140
class LinkTask(NamedTask):
138-
def __init__(self, task_name, extra_commands, orchestration=True, **kwargs):
141+
def __init__(self, task_name, suffix_commands, orchestration=True, **kwargs):
139142
if orchestration == 'ssl':
140143
bootstrap_commands = [bootstrap(SSL=1)]
141144
elif orchestration:
@@ -147,7 +150,7 @@ def __init__(self, task_name, extra_commands, orchestration=True, **kwargs):
147150
task_name=task_name,
148151
depends_on=OD([('name', 'make-release-archive'),
149152
('variant', 'releng')]),
150-
commands=bootstrap_commands + extra_commands,
153+
commands=bootstrap_commands + suffix_commands,
151154
**kwargs)
152155

153156

@@ -201,7 +204,7 @@ def __init__(self, task_name, extra_commands, orchestration=True, **kwargs):
201204
SpecialTask('debug-compile-coverage',
202205
tags=['debug-compile', 'coverage'],
203206
COVERAGE='ON',
204-
extra_commands=[func('upload coverage')]),
207+
suffix_commands=[func('upload coverage')]),
205208
CompileTask('debug-compile-no-counters',
206209
tags=['debug-compile', 'no-counters'],
207210
ENABLE_SHM_COUNTERS='OFF'),
@@ -244,7 +247,7 @@ def __init__(self, task_name, extra_commands, orchestration=True, **kwargs):
244247
continue_on_err=True,
245248
ANALYZE='ON',
246249
CC='clang',
247-
extra_commands=[
250+
suffix_commands=[
248251
func('upload scan artifacts'),
249252
shell_mongoc('''
250253
if find scan -name \*.html | grep -q html; then
@@ -300,70 +303,70 @@ def __init__(self, task_name, extra_commands, orchestration=True, **kwargs):
300303
tags=['debug-compile'],
301304
SRV='OFF'),
302305
LinkTask('link-with-cmake',
303-
extra_commands=[
306+
suffix_commands=[
304307
func('link sample program', BUILD_SAMPLE_WITH_CMAKE=1)]),
305308
LinkTask('link-with-cmake-ssl',
306-
extra_commands=[
309+
suffix_commands=[
307310
func('link sample program',
308311
BUILD_SAMPLE_WITH_CMAKE=1,
309312
ENABLE_SSL=1)]),
310313
LinkTask('link-with-cmake-snappy',
311-
extra_commands=[
314+
suffix_commands=[
312315
func('link sample program',
313316
BUILD_SAMPLE_WITH_CMAKE=1,
314317
ENABLE_SNAPPY=1)]),
315318
LinkTask('link-with-cmake-mac',
316-
extra_commands=[
319+
suffix_commands=[
317320
func('link sample program', BUILD_SAMPLE_WITH_CMAKE=1)]),
318321
LinkTask('link-with-cmake-deprecated',
319-
extra_commands=[
322+
suffix_commands=[
320323
func('link sample program',
321324
BUILD_SAMPLE_WITH_CMAKE=1,
322325
BUILD_SAMPLE_WITH_CMAKE_DEPRECATED=1)]),
323326
LinkTask('link-with-cmake-ssl-deprecated',
324-
extra_commands=[
327+
suffix_commands=[
325328
func('link sample program',
326329
BUILD_SAMPLE_WITH_CMAKE=1,
327330
BUILD_SAMPLE_WITH_CMAKE_DEPRECATED=1,
328331
ENABLE_SSL=1)]),
329332
LinkTask('link-with-cmake-snappy-deprecated',
330-
extra_commands=[
333+
suffix_commands=[
331334
func('link sample program',
332335
BUILD_SAMPLE_WITH_CMAKE=1,
333336
BUILD_SAMPLE_WITH_CMAKE_DEPRECATED=1,
334337
ENABLE_SNAPPY=1)]),
335338
LinkTask('link-with-cmake-mac-deprecated',
336-
extra_commands=[
339+
suffix_commands=[
337340
func('link sample program',
338341
BUILD_SAMPLE_WITH_CMAKE=1,
339342
BUILD_SAMPLE_WITH_CMAKE_DEPRECATED=1)]),
340343
LinkTask('link-with-cmake-windows',
341-
extra_commands=[func('link sample program MSVC')]),
344+
suffix_commands=[func('link sample program MSVC')]),
342345
LinkTask('link-with-cmake-windows-ssl',
343-
extra_commands=[func('link sample program MSVC', ENABLE_SSL=1)],
346+
suffix_commands=[func('link sample program MSVC', ENABLE_SSL=1)],
344347
orchestration='ssl'),
345348
LinkTask('link-with-cmake-windows-snappy',
346-
extra_commands=[
349+
suffix_commands=[
347350
func('link sample program MSVC', ENABLE_SNAPPY=1)]),
348351
LinkTask('link-with-cmake-mingw',
349-
extra_commands=[func('link sample program mingw')]),
352+
suffix_commands=[func('link sample program mingw')]),
350353
LinkTask('link-with-pkg-config',
351-
extra_commands=[func('link sample program')]),
354+
suffix_commands=[func('link sample program')]),
352355
LinkTask('link-with-pkg-config-mac',
353-
extra_commands=[func('link sample program')]),
356+
suffix_commands=[func('link sample program')]),
354357
LinkTask('link-with-pkg-config-ssl',
355-
extra_commands=[func('link sample program', ENABLE_SSL=1)]),
358+
suffix_commands=[func('link sample program', ENABLE_SSL=1)]),
356359
LinkTask('link-with-bson',
357-
extra_commands=[func('link sample program bson')],
360+
suffix_commands=[func('link sample program bson')],
358361
orchestration=False),
359362
LinkTask('link-with-bson-mac',
360-
extra_commands=[func('link sample program bson')],
363+
suffix_commands=[func('link sample program bson')],
361364
orchestration=False),
362365
LinkTask('link-with-bson-windows',
363-
extra_commands=[func('link sample program MSVC bson')],
366+
suffix_commands=[func('link sample program MSVC bson')],
364367
orchestration=False),
365368
LinkTask('link-with-bson-mingw',
366-
extra_commands=[func('link sample program mingw bson')],
369+
suffix_commands=[func('link sample program mingw bson')],
367370
orchestration=False),
368371
NamedTask('debian-package-build',
369372
commands=[
@@ -408,7 +411,10 @@ def __init__(self, task_name, extra_commands, orchestration=True, **kwargs):
408411
CompileWithClientSideEncryption('debug-compile-sasl-winssl-cse', tags=[
409412
'debug-compile', 'sasl', 'winssl'], SASL="AUTO", SSL="WINDOWS"),
410413
CompileWithClientSideEncryptionAsan('debug-compile-asan-openssl-cse', tags=[
411-
'debug-compile', 'asan-clang'], SSL="OPENSSL")
414+
'debug-compile', 'asan-clang'], SSL="OPENSSL"),
415+
CompileTask ('debug-compile-nosasl-openssl-1.0.1',
416+
prefix_commands=[func("install ssl", SSL="openssl-1.0.1u")],
417+
CFLAGS="-Wno-redundant-decls", SSL="OPENSSL", SASL="OFF")
412418
]
413419

414420

@@ -667,11 +673,11 @@ def _compressor_list(self):
667673

668674
class SpecialIntegrationTask(NamedTask):
669675
def __init__(self, task_name, depends_on='debug-compile-sasl-openssl',
670-
extra_commands=None, uri=None,
676+
suffix_commands=None, uri=None,
671677
tags=None, version='latest', topology='server'):
672678
commands = [func('fetch build', BUILD_NAME=depends_on),
673679
bootstrap(VERSION=version, TOPOLOGY=topology),
674-
run_tests(uri)] + (extra_commands or [])
680+
run_tests(uri)] + (suffix_commands or [])
675681
super(SpecialIntegrationTask, self).__init__(task_name,
676682
commands=commands,
677683
depends_on=depends_on,
@@ -824,7 +830,7 @@ def name(self):
824830
SSLTask('openssl-1.0.2', 'l'),
825831
SSLTask('openssl-1.1.0', 'f'),
826832
SSLTask('libressl-2.5', '.2', require_tls12=True),
827-
SSLTask('libressl-3.0', '.2', require_tls12=True, enable_ssl="AUTO"),
833+
SSLTask('libressl-3.0', '.2', require_tls12=True, enable_ssl="AUTO", cflags="-Wno-redundant-decls"),
828834
SSLTask('libressl-3.0', '.2', require_tls12=True),
829835
])
830836

@@ -900,7 +906,7 @@ class OCSPTask(MatrixTask):
900906
axes = OD([('test', ['test_1', 'test_2', 'test_3', 'test_4', 'soft_fail_test', 'malicious_server_test_1', 'malicious_server_test_2', 'cache']),
901907
('delegate', ['delegate', 'nodelegate']),
902908
('cert', ['rsa', 'ecdsa']),
903-
('ssl', ['openssl', 'darwinssl', 'winssl'])])
909+
('ssl', ['openssl', 'openssl-1.0.1', 'darwinssl', 'winssl'])])
904910

905911
name_prefix = 'test-ocsp'
906912

@@ -942,11 +948,9 @@ def to_dict(self):
942948

943949
# Testing in OCSP has a lot of exceptions.
944950
def _check_allowed(self):
945-
# Current latest macOS does not support the disableStapling failpoint.
946-
# There are no tests that can run on macOS in current evergreen configuration.
947951
if self.ssl == 'darwinssl':
948-
# TODO: remove this when macOS latest download is updated
949-
prohibit (True)
952+
# Secure Transport quietly ignores a must-staple certificate with no stapled response.
953+
prohibit (self.test == 'malicious_server_test_2')
950954

951955
# ECDSA certs can't be loaded (in the PEM format they're stored) on Windows/macOS. Skip them.
952956
if self.ssl == 'darwinssl' or self.ssl == 'winssl':
@@ -959,9 +963,6 @@ def _check_allowed(self):
959963
if self.test == 'soft_fail_test' or self.test == 'malicious_server_test_2' or self.test == 'cache':
960964
prohibit(self.delegate == 'delegate')
961965

962-
# Until OCSP is supported in OpenSSL, skip tests that expect to be revoked.
963-
if self.ssl == 'openssl':
964-
prohibit (self.test in ['test_2', 'test_4', 'malicious_server_test_1', 'malicious_server_test_2'])
965966

966967

967968
all_tasks = chain(all_tasks, OCSPTask.matrix())

build/evergreen_config_lib/variants.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -573,11 +573,13 @@ def days(n):
573573
batchtime=days(1)),
574574
Variant ('ocsp', 'OCSP tests', 'ubuntu1804-test', [
575575
OD([('name', 'debug-compile-nosasl-openssl'), ('distros', ['ubuntu1804-test'])]),
576-
#OD([('name', 'debug-compile-nosasl-darwinssl'), ('distros', ['macos-1014'])]),
576+
OD([('name', 'debug-compile-nosasl-darwinssl'), ('distros', ['macos-1014'])]),
577577
OD([('name', 'debug-compile-nosasl-winssl'), ('distros', ['windows-64-vs2017-test'])]),
578578
OD([('name', '.ocsp-openssl'), ('distros', ['ubuntu1804-test'])]),
579-
#OD([('name', '.ocsp-darwinssl'), ('distros', ['macos-1014'])]),
580-
OD([('name', '.ocsp-winssl'), ('distros', ['windows-64-vs2017-test'])])
579+
OD([('name', '.ocsp-darwinssl'), ('distros', ['macos-1014'])]),
580+
OD([('name', '.ocsp-winssl'), ('distros', ['windows-64-vs2017-test'])]),
581+
OD([('name', 'debug-compile-nosasl-openssl-1.0.1'), ('distros', ['ubuntu1804-test'])]),
582+
OD([('name', '.ocsp-openssl-1.0.1'), ('distros', ['ubuntu1804-test'])])
581583
], {}, batchtime=days(14)),
582584
Variant ('packaging', 'Linux Distro Packaging', 'ubuntu1604-test', [
583585
'debian-package-build',

src/libmongoc/CMakeLists.txt

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -629,10 +629,8 @@ if (NOT ENABLE_SSL STREQUAL OFF)
629629
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-stream-tls-openssl.c
630630
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-stream-tls-openssl-bio.c
631631
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-openssl.c
632+
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-ocsp-cache.c
632633
)
633-
if (OPENSSL_VERSION GREATER 1.1.1 OR OPENSSL_VERSION EQUAL 1.1.1)
634-
set (SOURCES ${SOURCES} ${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-ocsp-cache.c)
635-
endif()
636634
set (SSL_LIBRARIES ${OPENSSL_LIBRARIES})
637635
include_directories (${OPENSSL_INCLUDE_DIR})
638636
if (WIN32)
@@ -950,10 +948,8 @@ if (MONGOC_ENABLE_SSL)
950948
${PROJECT_SOURCE_DIR}/tests/test-mongoc-stream-tls-error.c
951949
${PROJECT_SOURCE_DIR}/tests/test-mongoc-stream-tls.c
952950
${PROJECT_SOURCE_DIR}/tests/test-mongoc-x509.c
951+
${PROJECT_SOURCE_DIR}/tests/test-mongoc-ocsp-cache.c
953952
)
954-
if (OPENSSL_VERSION GREATER 1.1.1 OR OPENSSL_VERSION EQUAL 1.1.1)
955-
set (test-libmongoc-sources ${test-libmongoc-sources} ${PROJECT_SOURCE_DIR}/tests/test-mongoc-ocsp-cache.c)
956-
endif()
957953
endif ()
958954

959955
if (MONGOC_ENABLE_SASL_CYRUS)

src/libmongoc/doc/configuring_tls.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,10 @@ Ensure your system's OpenSSL is a recent version (at least 1.0.1), or install a
8888

8989
When compiled against OpenSSL, the driver will attempt to load the system default certificate store, as configured by the distribution. That can be overridden by setting the ``tlsCAFile`` URI option or with the fields ``ca_file`` and ``ca_dir`` in the :symbol:`mongoc_ssl_opt_t`.
9090

91-
Setting ``tlsDisableOCSPEndpointCheck`` and ``tlsDisableCertificateRevocationCheck`` has no effect.
91+
Setting ``tlsDisableCertificateRevocationCheck`` disables OCSP revocation checking.
92+
Setting ``tlsDisableOCSPEndpointCheck`` disables OCSP responders from being contacted when OCSP revocation checking is enabled, and a server presents a certificate without stapled OCSP response.
9293

93-
The Online Certificate Status Protocol (OCSP) is partially supported (see `RFC 6960 <https://tools.ietf.org/html/rfc6960>`_). Support requires OpenSSL 1.1.0 and has the following behavior:
94+
The Online Certificate Status Protocol (OCSP) is partially supported (see `RFC 6960 <https://tools.ietf.org/html/rfc6960>`_). Support requires OpenSSL 1.0.1 and has the following behavior:
9495

9596
- Stapled OCSP responses are validated on certificates presented by the server.
9697
- Server certificates with a Must-Staple extension (see `RFC 7633 <https://tools.ietf.org/html/rfc7633>`_) are required to have stapled responses.

src/libmongoc/src/mongoc/mongoc-ocsp-cache.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,26 @@ update_entry (cache_entry_list_t *entry,
8080
entry->cert_status = cert_status;
8181
entry->reason = reason;
8282
}
83+
84+
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
85+
static int
86+
_cmp_time (ASN1_TIME *a, ASN1_TIME *b)
87+
{
88+
return ASN1_TIME_compare (a, b);
89+
}
90+
#else
91+
static int
92+
_cmp_time (ASN1_TIME *a, ASN1_TIME *b)
93+
{
94+
/* For older OpenSSL, always report that "a" is before "b". I.e. do not
95+
* replace the entry.
96+
* If a driver would accept a stapled OCSP response and that response has a
97+
* later nextUpdate than the response already in the cache, drivers SHOULD
98+
* replace the older entry in the cache with the fresher response. */
99+
return -1;
100+
}
101+
#endif
102+
83103
void
84104
_mongoc_ocsp_cache_set_resp (OCSP_CERTID *id,
85105
int cert_status,
@@ -96,8 +116,7 @@ _mongoc_ocsp_cache_set_resp (OCSP_CERTID *id,
96116
entry->id = OCSP_CERTID_dup (id);
97117
LL_APPEND (cache, entry);
98118
update_entry (entry, cert_status, reason, this_update, next_update);
99-
} else if (next_update &&
100-
ASN1_TIME_compare (next_update, entry->next_update) == 1) {
119+
} else if (next_update && _cmp_time (next_update, entry->next_update) == 1) {
101120
update_entry (entry, cert_status, reason, this_update, next_update);
102121
} else {
103122
/* Do nothing; our next_update is at a later date */

src/libmongoc/src/mongoc/mongoc-openssl-private.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@
2525
#include <openssl/err.h>
2626

2727
#include "mongoc-ssl.h"
28+
#include "mongoc-stream-tls-openssl-private.h"
2829

29-
#if (OPENSSL_VERSION_NUMBER >= 0x10101000L) && !defined(OPENSSL_NO_OCSP) && \
30+
#if (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_OCSP) && \
3031
!defined(LIBRESSL_VERSION_NUMBER)
3132
#define MONGOC_ENABLE_OCSP_OPENSSL
3233
#endif
@@ -35,9 +36,9 @@
3536
BSON_BEGIN_DECLS
3637

3738
bool
38-
_mongoc_openssl_check_cert (SSL *ssl,
39-
const char *host,
40-
bool allow_invalid_hostname);
39+
_mongoc_openssl_check_peer_hostname (SSL *ssl,
40+
const char *host,
41+
bool allow_invalid_hostname);
4142
SSL_CTX *
4243
_mongoc_openssl_ctx_new (mongoc_ssl_opt_t *opt);
4344
char *
@@ -49,9 +50,11 @@ _mongoc_openssl_cleanup (void);
4950

5051
#ifdef MONGOC_ENABLE_OCSP_OPENSSL
5152
int
52-
_mongoc_ocsp_tlsext_status_cb (SSL *ssl, void *arg);
53+
_mongoc_ocsp_tlsext_status (SSL *ssl, mongoc_openssl_ocsp_opt_t *opts);
5354
#endif
5455

56+
bool
57+
_mongoc_tlsfeature_has_status_request (const uint8_t *data, int length);
5558

5659
BSON_END_DECLS
5760

0 commit comments

Comments
 (0)