proxygen
folly::ssl::OpenSSLUtils Class Reference

#include <OpenSSLUtils.h>

Static Public Member Functions

static bool getTLSMasterKey (const SSL_SESSION *session, MutableByteRange keyOut)
 
static bool getTLSClientRandom (const SSL *ssl, MutableByteRange randomOut)
 
static bool validatePeerCertNames (X509 *cert, const sockaddr *addr, socklen_t addrLen)
 
static bool getPeerAddressFromX509StoreCtx (X509_STORE_CTX *ctx, sockaddr_storage *addrStorage, socklen_t *addrLen)
 
static const std::stringgetCipherName (uint16_t cipherCode)
 
static void setSSLInitialCtx (SSL *ssl, SSL_CTX *ctx)
 
static SSL_CTX * getSSLInitialCtx (SSL *ssl)
 
static std::string getCommonName (X509 *x509)
 
static BioMethodUniquePtr newSocketBioMethod ()
 
static bool setCustomBioReadMethod (BIO_METHOD *bioMeth, int(*meth)(BIO *, char *, int))
 
static bool setCustomBioWriteMethod (BIO_METHOD *bioMeth, int(*meth)(BIO *, const char *, int))
 
static int getBioShouldRetryWrite (int ret)
 
static void setBioAppData (BIO *b, void *ptr)
 
static void * getBioAppData (BIO *b)
 
static int getBioFd (BIO *b, int *fd)
 
static void setBioFd (BIO *b, int fd, int flags)
 

Detailed Description

Definition at line 26 of file OpenSSLUtils.h.

Member Function Documentation

void * folly::ssl::OpenSSLUtils::getBioAppData ( BIO *  b)
static

Definition at line 284 of file OpenSSLUtils.cpp.

Referenced by folly::AsyncSSLSocket::bioRead(), and folly::AsyncSSLSocket::bioWrite().

284  {
285 #ifdef OPENSSL_IS_BORINGSSL
286  return BIO_get_callback_arg(b);
287 #else
288  return BIO_get_app_data(b);
289 #endif
290 }
char b
int folly::ssl::OpenSSLUtils::getBioFd ( BIO *  b,
int *  fd 
)
static

Definition at line 292 of file OpenSSLUtils.cpp.

Referenced by folly::AsyncSSLSocket::bioRead(), and folly::AsyncSSLSocket::bioWrite().

292  {
293 #ifdef _WIN32
294  int ret = portability::sockets::socket_to_fd((SOCKET)BIO_get_fd(b, fd));
295  if (fd != nullptr) {
296  *fd = ret;
297  }
298  return ret;
299 #else
300  return BIO_get_fd(b, fd);
301 #endif
302 }
char b
int folly::ssl::OpenSSLUtils::getBioShouldRetryWrite ( int  ret)
static

Definition at line 266 of file OpenSSLUtils.cpp.

Referenced by folly::AsyncSSLSocket::bioRead(), and folly::AsyncSSLSocket::bioWrite().

266  {
267  int ret = 0;
268 #ifdef OPENSSL_IS_BORINGSSL
269  ret = boringssl_bio_fd_should_retry(r);
270 #else
271  ret = BIO_sock_should_retry(r);
272 #endif
273  return ret;
274 }
const std::string & folly::ssl::OpenSSLUtils::getCipherName ( uint16_t  cipherCode)
static

Get a stringified cipher name (e.g., ECDHE-ECDSA-CHACHA20-POLY1305) given the 2-byte code (e.g., 0xcca9) for the cipher. The name conversion only works for the ciphers built into the linked OpenSSL library

Parameters
cipherCodeA 16-bit IANA cipher code (machine endianness)
Returns
Cipher name, or empty if the code is not found

Definition at line 188 of file OpenSSLUtils.cpp.

References folly::empty(), folly::ssl::getOpenSSLCipherNames(), and string.

Referenced by folly::AsyncSSLSocket::getSSLClientCiphers().

188  {
189  // Having this in a hash map saves the binary search inside OpenSSL
190  static std::unordered_map<uint16_t, std::string> cipherCodeToName(
192 
193  const auto& iter = cipherCodeToName.find(cipherCode);
194  if (iter != cipherCodeToName.end()) {
195  return iter->second;
196  } else {
197  static std::string empty("");
198  return empty;
199  }
200 }
constexpr auto empty(C const &c) -> decltype(c.empty())
Definition: Access.h:55
const char * string
Definition: Conv.cpp:212
static std::unordered_map< uint16_t, std::string > getOpenSSLCipherNames()
std::string folly::ssl::OpenSSLUtils::getCommonName ( X509 *  x509)
static

Get the common name out of a cert. Return empty if x509 is null.

Definition at line 317 of file OpenSSLUtils.cpp.

References i, and string.

317  {
318  if (x509 == nullptr) {
319  return "";
320  }
321  X509_NAME* subject = X509_get_subject_name(x509);
322  std::string cn;
323  cn.resize(ub_common_name);
324  X509_NAME_get_text_by_NID(
325  subject, NID_commonName, const_cast<char*>(cn.data()), ub_common_name);
326  return cn;
327 }
const char * string
Definition: Conv.cpp:212
bool folly::ssl::OpenSSLUtils::getPeerAddressFromX509StoreCtx ( X509_STORE_CTX *  ctx,
sockaddr_storage *  addrStorage,
socklen_t *  addrLen 
)
static

Get the peer socket address from an X509_STORE_CTX*. Unlike the accept, getsockname, getpeername, etc family of operations, addrLen's initial value is ignored and reset.

Parameters
ctxContext from which to retrieve peer sockaddr
addrStorageout param for address
addrLenout param for length of address
Returns
true on success, false on failure

Definition at line 75 of file OpenSSLUtils.cpp.

References folly::netops::getpeername().

78  {
79  // Grab the ssl idx and then the ssl object so that we can get the peer
80  // name to compare against the ips in the subjectAltName
81  auto sslIdx = SSL_get_ex_data_X509_STORE_CTX_idx();
82  auto ssl = reinterpret_cast<SSL*>(X509_STORE_CTX_get_ex_data(ctx, sslIdx));
83  int fd = SSL_get_fd(ssl);
84  if (fd < 0) {
85  LOG(ERROR) << "Inexplicably couldn't get fd from SSL";
86  return false;
87  }
88 
89  *addrLen = sizeof(*addrStorage);
90  if (getpeername(fd, reinterpret_cast<sockaddr*>(addrStorage), addrLen) != 0) {
91  PLOG(ERROR) << "Unable to get peer name";
92  return false;
93  }
94  CHECK(*addrLen <= sizeof(*addrStorage));
95  return true;
96 }
int getpeername(NetworkSocket s, sockaddr *name, socklen_t *namelen)
Definition: NetOps.cpp:104
SSL_CTX * folly::ssl::OpenSSLUtils::getSSLInitialCtx ( SSL *  ssl)
static

Definition at line 215 of file OpenSSLUtils.cpp.

Referenced by folly::AsyncSSLSocket::sslAccept().

215  {
216  (void)ssl;
217 #if !FOLLY_OPENSSL_IS_110 && !defined(OPENSSL_NO_TLSEXT)
218  if (ssl) {
219  return ssl->initial_ctx;
220  }
221 #endif
222  return nullptr;
223 }
bool folly::ssl::OpenSSLUtils::getTLSClientRandom ( const SSL *  ssl,
MutableByteRange  randomOut 
)
static

Definition at line 58 of file OpenSSLUtils.cpp.

References folly::Range< Iter >::begin(), folly::copy(), and folly::Range< Iter >::size().

60  {
61 #if FOLLY_OPENSSL_IS_101 || FOLLY_OPENSSL_IS_102
62  if ((SSL_version(ssl) >> 8) == TLS1_VERSION_MAJOR && ssl->s3 &&
63  randomOut.size() == SSL3_RANDOM_SIZE) {
64  auto clientRandom = ssl->s3->client_random;
65  std::copy(clientRandom, clientRandom + SSL3_RANDOM_SIZE, randomOut.begin());
66  return true;
67  }
68 #else
69  (void)ssl;
70  (void)randomOut;
71 #endif
72  return false;
73 }
constexpr std::decay< T >::type copy(T &&value) noexcept(noexcept(typename std::decay< T >::type(std::forward< T >(value))))
Definition: Utility.h:72
bool folly::ssl::OpenSSLUtils::getTLSMasterKey ( const SSL_SESSION *  session,
MutableByteRange  keyOut 
)
static

Definition at line 40 of file OpenSSLUtils.cpp.

References folly::Range< Iter >::begin(), folly::copy(), and folly::Range< Iter >::size().

42  {
43 #if FOLLY_OPENSSL_IS_101 || FOLLY_OPENSSL_IS_102
44  if (session &&
45  session->master_key_length == static_cast<int>(keyOut.size())) {
46  auto masterKey = session->master_key;
47  std::copy(
48  masterKey, masterKey + session->master_key_length, keyOut.begin());
49  return true;
50  }
51 #else
52  (void)session;
53  (void)keyOut;
54 #endif
55  return false;
56 }
constexpr std::decay< T >::type copy(T &&value) noexcept(noexcept(typename std::decay< T >::type(std::forward< T >(value))))
Definition: Utility.h:72
BioMethodUniquePtr folly::ssl::OpenSSLUtils::newSocketBioMethod ( )
static

Wrappers for BIO operations that may be different across different versions/flavors of OpenSSL (including forks like BoringSSL)

Definition at line 225 of file OpenSSLUtils.cpp.

References folly::portability::ssl::BIO_meth_new(), folly::portability::ssl::BIO_meth_set_create(), folly::portability::ssl::BIO_meth_set_ctrl(), folly::portability::ssl::BIO_meth_set_destroy(), folly::portability::ssl::BIO_meth_set_gets(), folly::portability::ssl::BIO_meth_set_puts(), folly::portability::ssl::BIO_meth_set_read(), and folly::portability::ssl::BIO_meth_set_write().

225  {
226  BIO_METHOD* newmeth = nullptr;
227 #if FOLLY_OPENSSL_IS_110
228  if (!(newmeth = BIO_meth_new(BIO_TYPE_SOCKET, "socket_bio_method"))) {
229  return nullptr;
230  }
231  auto meth = const_cast<BIO_METHOD*>(BIO_s_socket());
232  BIO_meth_set_create(newmeth, BIO_meth_get_create(meth));
233  BIO_meth_set_destroy(newmeth, BIO_meth_get_destroy(meth));
234  BIO_meth_set_ctrl(newmeth, BIO_meth_get_ctrl(meth));
235  BIO_meth_set_callback_ctrl(newmeth, BIO_meth_get_callback_ctrl(meth));
236  BIO_meth_set_read(newmeth, BIO_meth_get_read(meth));
237  BIO_meth_set_write(newmeth, BIO_meth_get_write(meth));
238  BIO_meth_set_gets(newmeth, BIO_meth_get_gets(meth));
239  BIO_meth_set_puts(newmeth, BIO_meth_get_puts(meth));
240 #else
241  if (!(newmeth = (BIO_METHOD*)OPENSSL_malloc(sizeof(BIO_METHOD)))) {
242  return nullptr;
243  }
244  memcpy(newmeth, BIO_s_socket(), sizeof(BIO_METHOD));
245 #endif
246 
247  return BioMethodUniquePtr(newmeth);
248 }
int BIO_meth_set_destroy(BIO_METHOD *biom, int(*destroy)(BIO *))
Definition: OpenSSL.cpp:166
int BIO_meth_set_create(BIO_METHOD *biom, int(*create)(BIO *))
Definition: OpenSSL.cpp:161
int BIO_meth_set_write(BIO_METHOD *biom, int(*write)(BIO *, const char *, int))
Definition: OpenSSL.cpp:141
int BIO_meth_set_gets(BIO_METHOD *biom, int(*bgets)(BIO *, char *, int))
Definition: OpenSSL.cpp:151
int BIO_meth_set_ctrl(BIO_METHOD *biom, long(*ctrl)(BIO *, int, long, void *))
Definition: OpenSSL.cpp:156
BIO_METHOD * BIO_meth_new(int type, const char *name)
Definition: OpenSSL.cpp:121
std::unique_ptr< BIO_METHOD, BioMethodDeleter > BioMethodUniquePtr
int BIO_meth_set_puts(BIO_METHOD *biom, int(*bputs)(BIO *, const char *))
Definition: OpenSSL.cpp:146
int BIO_meth_set_read(BIO_METHOD *biom, int(*read)(BIO *, char *, int))
Definition: OpenSSL.cpp:136
void folly::ssl::OpenSSLUtils::setBioAppData ( BIO *  b,
void *  ptr 
)
static

Definition at line 276 of file OpenSSLUtils.cpp.

Referenced by folly::AsyncSSLSocket::setupSSLBio().

276  {
277 #ifdef OPENSSL_IS_BORINGSSL
278  BIO_set_callback_arg(b, static_cast<char*>(ptr));
279 #else
280  BIO_set_app_data(b, ptr);
281 #endif
282 }
void * ptr
char b
void folly::ssl::OpenSSLUtils::setBioFd ( BIO *  b,
int  fd,
int  flags 
)
static

Definition at line 304 of file OpenSSLUtils.cpp.

References folly::netops::socket().

Referenced by folly::AsyncSSLSocket::setupSSLBio().

304  {
305 #ifdef _WIN32
306  SOCKET socket = portability::sockets::fd_to_socket(fd);
307  // Internally OpenSSL uses this as an int for reasons completely
308  // beyond any form of sanity, so we do the cast ourselves to avoid
309  // the warnings that would be generated.
310  int sock = int(socket);
311 #else
312  int sock = fd;
313 #endif
314  BIO_set_fd(b, sock, flags);
315 }
flags
Definition: http_parser.h:127
char b
NetworkSocket socket(int af, int type, int protocol)
Definition: NetOps.cpp:412
bool folly::ssl::OpenSSLUtils::setCustomBioReadMethod ( BIO_METHOD *  bioMeth,
int(*)(BIO *, char *, int)  meth 
)
static

Definition at line 250 of file OpenSSLUtils.cpp.

References folly::portability::ssl::BIO_meth_set_read().

252  {
253  bool ret = false;
254  ret = (BIO_meth_set_read(bioMeth, meth) == 1);
255  return ret;
256 }
int BIO_meth_set_read(BIO_METHOD *biom, int(*read)(BIO *, char *, int))
Definition: OpenSSL.cpp:136
bool folly::ssl::OpenSSLUtils::setCustomBioWriteMethod ( BIO_METHOD *  bioMeth,
int(*)(BIO *, const char *, int)  meth 
)
static

Definition at line 258 of file OpenSSLUtils.cpp.

References folly::portability::ssl::BIO_meth_set_write().

260  {
261  bool ret = false;
262  ret = (BIO_meth_set_write(bioMeth, meth) == 1);
263  return ret;
264 }
int BIO_meth_set_write(BIO_METHOD *biom, int(*write)(BIO *, const char *, int))
Definition: OpenSSL.cpp:141
void folly::ssl::OpenSSLUtils::setSSLInitialCtx ( SSL *  ssl,
SSL_CTX *  ctx 
)
static

Set the 'initial_ctx' SSL_CTX* inside an SSL. The initial_ctx is used to point to the SSL_CTX on which servername callback and session callbacks, as well as session caching stats are set. If we want to enforce SSL_CTX thread-based ownership (e.g., thread-local SSL_CTX) in the application, we need to also set/reset the initial_ctx when we call SSL_set_SSL_CTX.

Parameters
sslSSL pointer
ctxSSL_CTX pointer
Returns
Cipher name, or empty if the code is not found

Definition at line 202 of file OpenSSLUtils.cpp.

Referenced by folly::AsyncSSLSocket::sslAccept().

202  {
203  (void)ssl;
204  (void)ctx;
205 #if !FOLLY_OPENSSL_IS_110 && !defined(OPENSSL_NO_TLSEXT)
206  if (ssl) {
207  if (ctx) {
208  SSL_CTX_up_ref(ctx);
209  }
210  ssl->initial_ctx = ctx;
211  }
212 #endif
213 }
bool folly::ssl::OpenSSLUtils::validatePeerCertNames ( X509 *  cert,
const sockaddr *  addr,
socklen_t  addrLen 
)
static

Validate that the peer certificate's common name or subject alt names match what we expect. Currently this only checks for IPs within subject alt names but it could easily be expanded to check common name and hostnames as well.

Parameters
certX509* peer certificate
addrsockaddr object containing sockaddr to verify
addrLenlength of sockaddr as returned by getpeername or accept
Returns
true iff a subject altname IP matches addr

Definition at line 98 of file OpenSSLUtils.cpp.

References addr, folly::FATAL, i, name, SCOPE_EXIT, folly::portability::ssl::STACK_OF(), and folly::WARNING.

101  {
102  // Try to extract the names within the SAN extension from the certificate
103  auto altNames = reinterpret_cast<STACK_OF(GENERAL_NAME)*>(
104  X509_get_ext_d2i(cert, NID_subject_alt_name, nullptr, nullptr));
105  SCOPE_EXIT {
106  if (altNames != nullptr) {
107  sk_GENERAL_NAME_pop_free(altNames, GENERAL_NAME_free);
108  }
109  };
110  if (altNames == nullptr) {
111  LOG(WARNING) << "No subjectAltName provided and we only support ip auth";
112  return false;
113  }
114 
115  const sockaddr_in* addr4 = nullptr;
116  const sockaddr_in6* addr6 = nullptr;
117  if (addr != nullptr) {
118  if (addr->sa_family == AF_INET) {
119  addr4 = reinterpret_cast<const sockaddr_in*>(addr);
120  } else if (addr->sa_family == AF_INET6) {
121  addr6 = reinterpret_cast<const sockaddr_in6*>(addr);
122  } else {
123  LOG(FATAL) << "Unsupported sockaddr family: " << addr->sa_family;
124  }
125  }
126 
127  for (int i = 0; i < sk_GENERAL_NAME_num(altNames); i++) {
128  auto name = sk_GENERAL_NAME_value(altNames, i);
129  if ((addr4 != nullptr || addr6 != nullptr) && name->type == GEN_IPADD) {
130  // Extra const-ness for paranoia
131  unsigned char const* const rawIpStr = name->d.iPAddress->data;
132  size_t const rawIpLen = size_t(name->d.iPAddress->length);
133 
134  if (rawIpLen == 4 && addr4 != nullptr) {
135  if (::memcmp(rawIpStr, &addr4->sin_addr, rawIpLen) == 0) {
136  return true;
137  }
138  } else if (rawIpLen == 16 && addr6 != nullptr) {
139  if (::memcmp(rawIpStr, &addr6->sin6_addr, rawIpLen) == 0) {
140  return true;
141  }
142  } else if (rawIpLen != 4 && rawIpLen != 16) {
143  LOG(WARNING) << "Unexpected IP length: " << rawIpLen;
144  }
145  }
146  }
147 
148  LOG(WARNING) << "Unable to match client cert against alt name ip";
149  return false;
150 }
STACK_OF(X509_OBJECT)*X509_STORE_get0_objects(X509_STORE *store)
Definition: OpenSSL.cpp:305
#define SCOPE_EXIT
Definition: ScopeGuard.h:274
const char * name
Definition: http_parser.c:437
ThreadPoolListHook * addr

The documentation for this class was generated from the following files: