summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/TLS/OpenSSL/OpenSSLContext.cpp')
-rw-r--r--Swiften/TLS/OpenSSL/OpenSSLContext.cpp233
1 files changed, 229 insertions, 4 deletions
diff --git a/Swiften/TLS/OpenSSL/OpenSSLContext.cpp b/Swiften/TLS/OpenSSL/OpenSSLContext.cpp
index 5692e74..e585766 100644
--- a/Swiften/TLS/OpenSSL/OpenSSLContext.cpp
+++ b/Swiften/TLS/OpenSSL/OpenSSLContext.cpp
@@ -42,6 +42,14 @@ namespace Swift {
42static const int MAX_FINISHED_SIZE = 4096; 42static const int MAX_FINISHED_SIZE = 4096;
43static const int SSL_READ_BUFFERSIZE = 8192; 43static const int SSL_READ_BUFFERSIZE = 8192;
44 44
45#define SSL_DEFAULT_VERIFY_DEPTH 5
46
47// Callback function declarations for certificate verification
48extern "C" {
49 static int certVerifyCallback(X509_STORE_CTX *store_ctx, void*);
50 static int verifyCallback(int preverify_ok, X509_STORE_CTX *ctx);
51}
52
45static void freeX509Stack(STACK_OF(X509)* stack) { 53static void freeX509Stack(STACK_OF(X509)* stack) {
46 sk_X509_free(stack); 54 sk_X509_free(stack);
47} 55}
@@ -90,7 +98,7 @@ namespace {
90 } 98 }
91 } 99 }
92 100
93OpenSSLContext::OpenSSLContext(Mode mode) : mode_(mode), state_(State::Start) { 101OpenSSLContext::OpenSSLContext(const TLSOptions& options, Mode mode) : mode_(mode), state_(State::Start) {
94 ensureLibraryInitialized(); 102 ensureLibraryInitialized();
95 context_ = createSSL_CTX(mode_); 103 context_ = createSSL_CTX(mode_);
96 SSL_CTX_set_options(context_.get(), SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); 104 SSL_CTX_set_options(context_.get(), SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
@@ -118,9 +126,9 @@ OpenSSLContext::OpenSSLContext(Mode mode) : mode_(mode), state_(State::Start) {
118 X509_STORE* store = SSL_CTX_get_cert_store(context_.get()); 126 X509_STORE* store = SSL_CTX_get_cert_store(context_.get());
119 HCERTSTORE systemStore = CertOpenSystemStore(0, "ROOT"); 127 HCERTSTORE systemStore = CertOpenSystemStore(0, "ROOT");
120 if (systemStore) { 128 if (systemStore) {
121 PCCERT_CONTEXT certContext = NULL; 129 PCCERT_CONTEXT certContext = nullptr;
122 while (true) { 130 while (true) {
123 certContext = CertFindCertificateInStore(systemStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, certContext); 131 certContext = CertFindCertificateInStore(systemStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_ANY, nullptr, certContext);
124 if (!certContext) { 132 if (!certContext) {
125 break; 133 break;
126 } 134 }
@@ -159,6 +167,7 @@ OpenSSLContext::OpenSSLContext(Mode mode) : mode_(mode), state_(State::Start) {
159 CFRelease(anchorCertificates); 167 CFRelease(anchorCertificates);
160 } 168 }
161#endif 169#endif
170 configure(options);
162} 171}
163 172
164OpenSSLContext::~OpenSSLContext() { 173OpenSSLContext::~OpenSSLContext() {
@@ -175,6 +184,222 @@ void OpenSSLContext::initAndSetBIOs() {
175 SSL_set_bio(handle_.get(), readBIO_, writeBIO_); 184 SSL_set_bio(handle_.get(), readBIO_, writeBIO_);
176} 185}
177 186
187// This callback is called by OpenSSL when a client certificate needs to be verified.
188// In turn, this calls the verification callback which the user
189// of this OpenSSLContext has configured (if any).
190static int certVerifyCallback(X509_STORE_CTX* store_ctx, void* arg)
191{
192 OpenSSLContext* context = static_cast<OpenSSLContext *>(arg);
193
194 // Need to stash store_ctx pointer for use within verification
195 context->setX509StoreContext(store_ctx);
196
197 int ret;
198
199 // This callback shouldn't have been set up if the context doesn't
200 // have a verifyCertCallback set, but it doesn't hurt to double check
201 std::function<int (const TLSContext *)> cb = context->getVerifyCertCallback();
202 if (cb != nullptr) {
203 ret = cb(static_cast<const OpenSSLContext*>(context));
204 } else {
205 SWIFT_LOG(warning) << "certVerifyCallback called but context.verifyCertCallback is unset" << std::endl;
206 ret = 0;
207 }
208
209 context->setX509StoreContext(nullptr);
210 return ret;
211}
212
213// Convenience function to generate a text representation
214// of an X509 Name. This information is only used for logging.
215static std::string X509_NAME_to_text(X509_NAME* name)
216{
217 std::string nameString;
218
219 if (!name) {
220 return nameString;
221 }
222
223 std::unique_ptr<BIO, decltype(&BIO_free)> io(BIO_new(BIO_s_mem()), &BIO_free);
224 int r = X509_NAME_print_ex(io.get(), name, 0, XN_FLAG_RFC2253);
225 BIO_write(io.get(), "\0", 1);
226
227 if (r > 0) {
228 BUF_MEM* ptr = nullptr;
229 BIO_get_mem_ptr(io.get(), &ptr);
230 nameString = ptr->data;
231 }
232
233 return nameString;
234}
235
236// Check depth of certificate chain
237static int verifyCallback(int preverifyOk, X509_STORE_CTX* ctx)
238{
239 // Retrieve the pointer to the SSL of the connection currently treated
240 // and the application specific data stored into the SSL object.
241
242 int err = X509_STORE_CTX_get_error(ctx);
243 int depth = X509_STORE_CTX_get_error_depth(ctx);
244
245 SSL* ssl = static_cast<SSL*>(X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
246 SSL_CTX* sslctx = ssl ? SSL_get_SSL_CTX(ssl) : nullptr;
247 if (!sslctx) {
248 SWIFT_LOG(error) << "verifyCallback: internal error" << std::endl;
249 return preverifyOk;
250 }
251
252 if (SSL_CTX_get_verify_mode(sslctx) == SSL_VERIFY_NONE) {
253 SWIFT_LOG(info) << "verifyCallback: no verification required" << std::endl;
254 // No verification requested
255 return 1;
256 }
257
258 X509* errCert = X509_STORE_CTX_get_current_cert(ctx);
259 std::string subjectString;
260 if (errCert) {
261 X509_NAME* subjectName = X509_get_subject_name(errCert);
262 subjectString = X509_NAME_to_text(subjectName);
263 }
264
265 // Catch a too long certificate chain. The depth limit set using
266 // SSL_CTX_set_verify_depth() is by purpose set to "limit+1" so
267 // that whenever the "depth>verify_depth" condition is met, we
268 // have violated the limit and want to log this error condition.
269 // We must do it here, because the CHAIN_TOO_LONG error would not
270 // be found explicitly; only errors introduced by cutting off the
271 // additional certificates would be logged.
272 if (depth >= SSL_CTX_get_verify_depth(sslctx)) {
273 preverifyOk = 0;
274 err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
275 X509_STORE_CTX_set_error(ctx, err);
276 }
277
278 if (!preverifyOk) {
279 std::string issuerString;
280 if (errCert) {
281 X509_NAME* issuerName = X509_get_issuer_name(errCert);
282 issuerString = X509_NAME_to_text(issuerName);
283 }
284 SWIFT_LOG(error) << "verifyCallback: verification error" <<
285 X509_verify_cert_error_string(err) << " depth: " <<
286 depth << " issuer: " << ((issuerString.length() > 0) ? issuerString : "<unknown>") << std::endl;
287 } else {
288 SWIFT_LOG(info) << "verifyCallback: SSL depth: " << depth << " Subject: " <<
289 ((subjectString.length() > 0) ? subjectString : "<>") << std::endl;
290 }
291 return preverifyOk;
292}
293
294bool OpenSSLContext::configure(const TLSOptions &options)
295{
296 if (options.cipherSuites) {
297 std::string cipherSuites = *(options.cipherSuites);
298 if (SSL_CTX_set_cipher_list(context_.get(), cipherSuites.c_str()) != 1 ) {
299 SWIFT_LOG(error) << "Failed to set cipher-suites" << std::endl;
300 return false;
301 }
302 }
303
304 if (options.context) {
305 const auto& contextId = *options.context;
306
307 if (SSL_CTX_set_session_id_context(context_.get(),
308 reinterpret_cast<const unsigned char *>(contextId.c_str()),
309 contextId.length()) != 1) {
310 SWIFT_LOG(error) << "Failed to set context-id" << std::endl;
311 return false;
312 }
313 }
314
315 if (options.sessionCacheTimeout) {
316 int scto = *options.sessionCacheTimeout;
317 if (scto <= 0) {
318 SWIFT_LOG(error) << "Invalid value for session-cache-timeout" << std::endl;
319 return false;
320 }
321 (void)SSL_CTX_set_timeout(context_.get(), scto);
322 if (SSL_CTX_get_timeout(context_.get()) != scto) {
323 SWIFT_LOG(error) << "Failed to set session-cache-timeout" << std::endl;
324 return false;
325 }
326 }
327
328 if (options.verifyCertificateCallback) {
329 verifyCertCallback = *options.verifyCertificateCallback;
330 } else {
331 verifyCertCallback = nullptr;
332 }
333
334 if (options.verifyMode) {
335 TLSOptions::VerifyMode verify_mode = *options.verifyMode;
336 int mode;
337 switch (verify_mode) {
338 case TLSOptions::VerifyMode::NONE:
339 mode = SSL_VERIFY_NONE;
340 break;
341 case TLSOptions::VerifyMode::REQUIRED:
342 mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | SSL_VERIFY_CLIENT_ONCE;
343 break;
344 case TLSOptions::VerifyMode::OPTIONAL:
345 mode = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE;
346 break;
347 }
348
349 // Set up default certificate chain verification depth - may be overridden below
350 SSL_CTX_set_verify_depth(context_.get(), SSL_DEFAULT_VERIFY_DEPTH + 1);
351
352 // Set callbacks up
353 SSL_CTX_set_verify(context_.get(), mode, verifyCallback);
354
355 // Only set up certificate verification callback if a user callback has
356 // been configured via the TLSOptions
357 if (verifyCertCallback != nullptr) {
358 SSL_CTX_set_cert_verify_callback(context_.get(), certVerifyCallback, this);
359 }
360 }
361
362 if (options.verifyDepth) {
363 int depth = *options.verifyDepth;
364 if (depth <= 0) {
365 SWIFT_LOG(error) << "Invalid value for verify-depth" << std::endl;
366 return false;
367 }
368
369 // Increase depth limit by one, so that verifyCallback() will log it
370 SSL_CTX_set_verify_depth(context_.get(), depth + 1);
371 }
372
373 auto updateOptionIfPresent = [this](boost::optional<bool> option, int flag) {
374 if (option) {
375 if (*option) {
376 SSL_CTX_set_options(context_.get(), flag);
377 }
378 else {
379 SSL_CTX_clear_options(context_.get(), flag);
380 }
381 }
382 };
383 updateOptionIfPresent(options.workaroundMicrosoftSessID, SSL_OP_MICROSOFT_SESS_ID_BUG);
384 updateOptionIfPresent(options.workaroundNetscapeChallenge, SSL_OP_NETSCAPE_CHALLENGE_BUG);
385 updateOptionIfPresent(options.workaroundNetscapeReuseCipherChange, SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG);
386 updateOptionIfPresent(options.workaroundSSLRef2ReuseCertType, SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG);
387 updateOptionIfPresent(options.workaroundMicrosoftBigSSLv3Buffer, SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER);
388 updateOptionIfPresent(options.workaroundSSLeay080ClientDH, SSL_OP_SSLEAY_080_CLIENT_DH_BUG);
389 updateOptionIfPresent(options.workaroundTLSD5, SSL_OP_TLS_D5_BUG);
390 updateOptionIfPresent(options.workaroundTLSBlockPadding, SSL_OP_TLS_BLOCK_PADDING_BUG);
391 updateOptionIfPresent(options.workaroundDontInsertEmptyFragments, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
392 updateOptionIfPresent(options.workaroundAll, SSL_OP_ALL);
393 updateOptionIfPresent(options.suppressSSLv2, SSL_OP_NO_SSLv2);
394 updateOptionIfPresent(options.suppressSSLv3, SSL_OP_NO_SSLv3);
395 updateOptionIfPresent(options.suppressTLSv1, SSL_OP_NO_TLSv1);
396 updateOptionIfPresent(options.disableTLSRollBackBug, SSL_OP_TLS_ROLLBACK_BUG);
397 updateOptionIfPresent(options.singleDHUse, SSL_OP_SINGLE_DH_USE);
398
399 return true;
400}
401
402
178void OpenSSLContext::accept() { 403void OpenSSLContext::accept() {
179 assert(mode_ == Mode::Server); 404 assert(mode_ == Mode::Server);
180 handle_ = std::unique_ptr<SSL>(SSL_new(context_.get())); 405 handle_ = std::unique_ptr<SSL>(SSL_new(context_.get()));
@@ -486,7 +711,7 @@ bool OpenSSLContext::setDiffieHellmanParameters(const ByteArray& parametersInOpe
486 if (bio) { 711 if (bio) {
487 BIO_write(bio.get(), vecptr(parametersInOpenSslDer), parametersInOpenSslDer.size()); 712 BIO_write(bio.get(), vecptr(parametersInOpenSslDer), parametersInOpenSslDer.size());
488 auto result = 0L; 713 auto result = 0L;
489 if (auto dhparams = d2i_DHparams_bio(bio.get(), NULL)) { 714 if (auto dhparams = d2i_DHparams_bio(bio.get(), nullptr)) {
490 if (handle_) { 715 if (handle_) {
491 result = SSL_set_tmp_dh(handle_.get(), dhparams); 716 result = SSL_set_tmp_dh(handle_.get(), dhparams);
492 } 717 }