proxygen
OpenSSLUtils.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2016-present Facebook, 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 
18 
19 #include <glog/logging.h>
20 
21 #include <unordered_map>
22 
23 #include <folly/ScopeGuard.h>
26 #include <folly/ssl/Init.h>
27 
28 namespace {
29 #ifdef OPENSSL_IS_BORINGSSL
30 // BoringSSL doesn't (as of May 2016) export the equivalent
31 // of BIO_sock_should_retry, so this is one way around it :(
32 static int boringssl_bio_fd_should_retry(int err);
33 #endif
34 
35 } // namespace
36 
37 namespace folly {
38 namespace ssl {
39 
41  const SSL_SESSION* session,
42  MutableByteRange keyOut) {
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 }
57 
59  const SSL* ssl,
60  MutableByteRange randomOut) {
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 }
74 
76  X509_STORE_CTX* ctx,
77  sockaddr_storage* addrStorage,
78  socklen_t* addrLen) {
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 }
97 
99  X509* cert,
100  const sockaddr* addr,
101  socklen_t /* addrLen */) {
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 }
151 
152 static std::unordered_map<uint16_t, std::string> getOpenSSLCipherNames() {
154  std::unordered_map<uint16_t, std::string> ret;
155  SSL_CTX* ctx = nullptr;
156  SSL* ssl = nullptr;
157 
158  const SSL_METHOD* meth = SSLv23_server_method();
159  OpenSSL_add_ssl_algorithms();
160 
161  if ((ctx = SSL_CTX_new(meth)) == nullptr) {
162  return ret;
163  }
164  SCOPE_EXIT {
165  SSL_CTX_free(ctx);
166  };
167 
168  if ((ssl = SSL_new(ctx)) == nullptr) {
169  return ret;
170  }
171  SCOPE_EXIT {
172  SSL_free(ssl);
173  };
174 
175  STACK_OF(SSL_CIPHER)* sk = SSL_get_ciphers(ssl);
176  for (int i = 0; i < sk_SSL_CIPHER_num(sk); i++) {
177  const SSL_CIPHER* c = sk_SSL_CIPHER_value(sk, i);
178  unsigned long id = SSL_CIPHER_get_id(c);
179  // OpenSSL 1.0.2 and prior does weird things such as stuff the SSL/TLS
180  // version into the top 16 bits. Let's ignore those for now. This is
181  // BoringSSL compatible (their id can be cast as uint16_t)
182  uint16_t cipherCode = id & 0xffffL;
183  ret[cipherCode] = SSL_CIPHER_get_name(c);
184  }
185  return ret;
186 }
187 
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 }
201 
202 void OpenSSLUtils::setSSLInitialCtx(SSL* ssl, SSL_CTX* ctx) {
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 }
214 
215 SSL_CTX* OpenSSLUtils::getSSLInitialCtx(SSL* ssl) {
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 }
224 
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 }
249 
251  BIO_METHOD* bioMeth,
252  int (*meth)(BIO*, char*, int)) {
253  bool ret = false;
254  ret = (BIO_meth_set_read(bioMeth, meth) == 1);
255  return ret;
256 }
257 
259  BIO_METHOD* bioMeth,
260  int (*meth)(BIO*, const char*, int)) {
261  bool ret = false;
262  ret = (BIO_meth_set_write(bioMeth, meth) == 1);
263  return ret;
264 }
265 
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 }
275 
276 void OpenSSLUtils::setBioAppData(BIO* b, void* ptr) {
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 }
283 
285 #ifdef OPENSSL_IS_BORINGSSL
286  return BIO_get_callback_arg(b);
287 #else
288  return BIO_get_app_data(b);
289 #endif
290 }
291 
292 int OpenSSLUtils::getBioFd(BIO* b, int* fd) {
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 }
303 
304 void OpenSSLUtils::setBioFd(BIO* b, int fd, int flags) {
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 }
316 
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 }
328 
329 } // namespace ssl
330 } // namespace folly
331 
332 namespace {
333 #ifdef OPENSSL_IS_BORINGSSL
334 
335 static int boringssl_bio_fd_non_fatal_error(int err) {
336  if (
337 #ifdef EWOULDBLOCK
338  err == EWOULDBLOCK ||
339 #endif
340 #ifdef WSAEWOULDBLOCK
341  err == WSAEWOULDBLOCK ||
342 #endif
343 #ifdef ENOTCONN
344  err == ENOTCONN ||
345 #endif
346 #ifdef EINTR
347  err == EINTR ||
348 #endif
349 #ifdef EAGAIN
350  err == EAGAIN ||
351 #endif
352 #ifdef EPROTO
353  err == EPROTO ||
354 #endif
355 #ifdef EINPROGRESS
356  err == EINPROGRESS ||
357 #endif
358 #ifdef EALREADY
359  err == EALREADY ||
360 #endif
361  0) {
362  return 1;
363  }
364  return 0;
365 }
366 
367 #if defined(OPENSSL_WINDOWS)
368 
369 int boringssl_bio_fd_should_retry(int i) {
370  if (i == -1) {
371  return boringssl_bio_fd_non_fatal_error((int)GetLastError());
372  }
373  return 0;
374 }
375 
376 #else // !OPENSSL_WINDOWS
377 
378 int boringssl_bio_fd_should_retry(int i) {
379  if (i == -1) {
380  return boringssl_bio_fd_non_fatal_error(errno);
381  }
382  return 0;
383 }
384 #endif // OPENSSL_WINDOWS
385 
386 #endif // OEPNSSL_IS_BORINGSSL
387 
388 } // namespace
static std::string getCommonName(X509 *x509)
void * ptr
static SSL_CTX * getSSLInitialCtx(SSL *ssl)
flags
Definition: http_parser.h:127
static bool getTLSMasterKey(const SSL_SESSION *session, MutableByteRange keyOut)
static bool setCustomBioReadMethod(BIO_METHOD *bioMeth, int(*meth)(BIO *, char *, int))
char b
int BIO_meth_set_destroy(BIO_METHOD *biom, int(*destroy)(BIO *))
Definition: OpenSSL.cpp:166
STACK_OF(X509_OBJECT)*X509_STORE_get0_objects(X509_STORE *store)
Definition: OpenSSL.cpp:305
static void * getBioAppData(BIO *b)
constexpr size_type size() const
Definition: Range.h:431
int BIO_meth_set_create(BIO_METHOD *biom, int(*create)(BIO *))
Definition: OpenSSL.cpp:161
void init()
Definition: Init.cpp:54
#define SCOPE_EXIT
Definition: ScopeGuard.h:274
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
static bool getTLSClientRandom(const SSL *ssl, MutableByteRange randomOut)
int BIO_meth_set_write(BIO_METHOD *biom, int(*write)(BIO *, const char *, int))
Definition: OpenSSL.cpp:141
static void setSSLInitialCtx(SSL *ssl, SSL_CTX *ctx)
int BIO_meth_set_gets(BIO_METHOD *biom, int(*bgets)(BIO *, char *, int))
Definition: OpenSSL.cpp:151
const char * name
Definition: http_parser.c:437
constexpr std::decay< T >::type copy(T &&value) noexcept(noexcept(typename std::decay< T >::type(std::forward< T >(value))))
Definition: Utility.h:72
static void setBioFd(BIO *b, int fd, int flags)
constexpr auto empty(C const &c) -> decltype(c.empty())
Definition: Access.h:55
int BIO_meth_set_ctrl(BIO_METHOD *biom, long(*ctrl)(BIO *, int, long, void *))
Definition: OpenSSL.cpp:156
static int getBioFd(BIO *b, int *fd)
static bool setCustomBioWriteMethod(BIO_METHOD *bioMeth, int(*meth)(BIO *, const char *, int))
static BioMethodUniquePtr newSocketBioMethod()
NetworkSocket socket(int af, int type, int protocol)
Definition: NetOps.cpp:412
static bool validatePeerCertNames(X509 *cert, const sockaddr *addr, socklen_t addrLen)
constexpr Iter begin() const
Definition: Range.h:452
static int getBioShouldRetryWrite(int ret)
const char * string
Definition: Conv.cpp:212
static bool getPeerAddressFromX509StoreCtx(X509_STORE_CTX *ctx, sockaddr_storage *addrStorage, socklen_t *addrLen)
int getpeername(NetworkSocket s, sockaddr *name, socklen_t *namelen)
Definition: NetOps.cpp:104
static void setBioAppData(BIO *b, void *ptr)
BIO_METHOD * BIO_meth_new(int type, const char *name)
Definition: OpenSSL.cpp:121
std::unique_ptr< BIO_METHOD, BioMethodDeleter > BioMethodUniquePtr
char c
ThreadPoolListHook * addr
static const std::string & getCipherName(uint16_t cipherCode)
int BIO_meth_set_puts(BIO_METHOD *biom, int(*bputs)(BIO *, const char *))
Definition: OpenSSL.cpp:146
static std::unordered_map< uint16_t, std::string > getOpenSSLCipherNames()
int BIO_meth_set_read(BIO_METHOD *biom, int(*read)(BIO *, char *, int))
Definition: OpenSSL.cpp:136