Coverage Report

Created: 2025-08-28 06:21

/src/libtorrent/src/ssl.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
3
Copyright (c) 2020, Paul-Louis Ageneau
4
Copyright (c) 2018, Alexandre Janniaux
5
Copyright (c) 2020, Arvid Norberg
6
All rights reserved.
7
8
Redistribution and use in source and binary forms, with or without
9
modification, are permitted provided that the following conditions
10
are met:
11
12
  * Redistributions of source code must retain the above copyright
13
    notice, this list of conditions and the following disclaimer.
14
  * Redistributions in binary form must reproduce the above copyright
15
    notice, this list of conditions and the following disclaimer in
16
    the documentation and/or other materials provided with the distribution.
17
  * Neither the name of the author nor the names of its
18
    contributors may be used to endorse or promote products derived
19
    from this software without specific prior written permission.
20
21
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
POSSIBILITY OF SUCH DAMAGE.
32
33
*/
34
35
#include "libtorrent/ssl.hpp"
36
37
#if TORRENT_USE_SSL
38
39
#ifdef TORRENT_USE_OPENSSL
40
#include <openssl/x509v3.h> // for GENERAL_NAME
41
#endif
42
43
#ifdef TORRENT_USE_GNUTLS
44
#include <gnutls/x509.h>
45
#endif
46
47
namespace libtorrent {
48
namespace ssl {
49
50
void set_trust_certificate(native_context_type nc, string_view pem, error_code &ec)
51
0
{
52
0
#if defined TORRENT_USE_OPENSSL
53
  // create a new X.509 certificate store
54
0
  X509_STORE* cert_store = X509_STORE_new();
55
0
  if (!cert_store)
56
0
  {
57
0
    ec = error_code(int(ERR_get_error()), error::get_ssl_category());
58
0
    return;
59
0
  }
60
61
  // wrap the PEM certificate in a BIO, for openssl to read
62
0
  BIO* bp = BIO_new_mem_buf(
63
0
      const_cast<char*>(pem.data()),
64
0
      int(pem.size()));
65
66
  // parse the certificate into OpenSSL's internal representation
67
0
  X509* cert = PEM_read_bio_X509_AUX(bp, nullptr, nullptr, nullptr);
68
0
  BIO_free(bp);
69
70
0
  if (!cert)
71
0
  {
72
0
    X509_STORE_free(cert_store);
73
0
    ec = error_code(int(ERR_get_error()), error::get_ssl_category());
74
0
    return;
75
0
  }
76
77
  // add cert to cert_store
78
0
  X509_STORE_add_cert(cert_store, cert);
79
0
  X509_free(cert);
80
81
  // and lastly, replace the default cert store with ours
82
0
  SSL_CTX_set_cert_store(nc, cert_store);
83
84
#elif defined TORRENT_USE_GNUTLS
85
    gnutls_datum_t ca;
86
    ca.data = reinterpret_cast<unsigned char*>(const_cast<char*>(pem.data()));
87
    ca.size = unsigned(pem.size());
88
89
  // Warning: returns the number of certificates processed or a negative error code on error
90
  int ret = gnutls_certificate_set_x509_trust_mem(nc, &ca, GNUTLS_X509_FMT_PEM);
91
  if(ret < 0)
92
    ec = error_code(ret, error::get_ssl_category());
93
#endif
94
0
}
95
96
void set_server_name_callback(context_handle_type c, server_name_callback_type cb, void* arg, error_code& ec)
97
0
{
98
0
#if defined TORRENT_USE_OPENSSL
99
0
  TORRENT_UNUSED(ec);
100
0
#if defined __clang__
101
0
#pragma clang diagnostic push
102
0
#pragma clang diagnostic ignored "-Wold-style-cast"
103
0
#pragma clang diagnostic ignored "-Wcast-function-type-strict"
104
0
#pragma clang diagnostic ignored "-Wunknown-warning-option"
105
0
#endif
106
0
  SSL_CTX_set_tlsext_servername_callback(c, cb);
107
0
  SSL_CTX_set_tlsext_servername_arg(c, arg);
108
0
#if defined __clang__
109
0
#pragma clang diagnostic pop
110
0
#endif
111
112
#elif defined TORRENT_USE_GNUTLS
113
  if(cb)
114
    c->set_server_name_callback(
115
        [cb, arg](stream_base& s, std::string const& name)
116
        {
117
          return cb(&s, name, arg);
118
        }
119
        , ec);
120
  else
121
    c->set_server_name_callback(nullptr);
122
#endif
123
0
}
124
125
void set_host_name(stream_handle_type s, std::string const& name, error_code& ec)
126
0
{
127
0
#if defined TORRENT_USE_OPENSSL
128
0
  TORRENT_UNUSED(ec);
129
0
#if defined __clang__
130
0
#pragma clang diagnostic push
131
0
#pragma clang diagnostic ignored "-Wold-style-cast"
132
0
#pragma clang diagnostic ignored "-Wcast-qual"
133
0
#endif
134
0
  SSL_set_tlsext_host_name(s, name.c_str());
135
0
#if defined __clang__
136
0
#pragma clang diagnostic pop
137
0
#endif
138
139
#elif defined TORRENT_USE_GNUTLS
140
  s->set_host_name(name, ec);
141
#endif
142
0
}
143
144
void set_context(stream_handle_type s, context_handle_type c)
145
0
{
146
0
#if defined TORRENT_USE_OPENSSL
147
0
  SSL_set_SSL_CTX(s, c);
148
0
  SSL_set_verify(s
149
0
    , SSL_CTX_get_verify_mode(c)
150
0
    , SSL_CTX_get_verify_callback(c));
151
#elif defined TORRENT_USE_GNUTLS
152
  s->set_context(*c);
153
#endif
154
0
}
155
156
bool has_context(stream_handle_type s, context_handle_type c)
157
0
{
158
0
  context_handle_type stream_ctx = get_context(s);
159
0
#if defined TORRENT_USE_OPENSSL
160
0
  return stream_ctx == c;
161
#elif defined TORRENT_USE_GNUTLS
162
  return stream_ctx->native_handle() == c->native_handle();
163
#endif
164
0
}
165
166
context_handle_type get_context(stream_handle_type s)
167
0
{
168
0
#if defined TORRENT_USE_OPENSSL
169
0
  return SSL_get_SSL_CTX(s);
170
#elif defined TORRENT_USE_GNUTLS
171
  return &s->get_context();
172
#endif
173
0
}
174
175
#if defined TORRENT_USE_OPENSSL
176
namespace {
177
  struct lifecycle
178
  {
179
    lifecycle()
180
2
    {
181
      // this is needed for openssl < 1.0 to decrypt keys created by openssl 1.0+
182
2
#if !defined(OPENSSL_API_COMPAT) || (OPENSSL_API_COMPAT < 0x10100000L)
183
2
      OpenSSL_add_all_algorithms();
184
#else
185
      OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS, nullptr);
186
#endif
187
2
    }
188
189
    ~lifecycle()
190
0
    {
191
// by openssl changelog at https://www.openssl.org/news/changelog.html
192
// Changes between 1.0.2h and 1.1.0  [25 Aug 2016]
193
// - Most global cleanup functions are no longer required because they are handled
194
//   via auto-deinit. Affected function CRYPTO_cleanup_all_ex_data()
195
0
#if !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < 0x10100000L
196
#ifdef TORRENT_MACOS_DEPRECATED_LIBCRYPTO
197
#pragma clang diagnostic push
198
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
199
#endif
200
      // openssl requires this to clean up internal structures it allocates
201
0
      CRYPTO_cleanup_all_ex_data();
202
#ifdef TORRENT_MACOS_DEPRECATED_LIBCRYPTO
203
#pragma clang diagnostic pop
204
#endif
205
0
#endif
206
0
    }
207
  } global;
208
}
209
#endif
210
211
} // ssl
212
} // libtorrent
213
#endif
214