text: /*
   * Copyright 2016-present Facebook, Inc.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *   http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  #pragma once
  
  #include <folly/Range.h>
  #include <folly/portability/OpenSSL.h>
  #include <folly/portability/Sockets.h>
  #include <folly/ssl/OpenSSLPtrTypes.h>
  
  namespace folly {
  namespace ssl {
  
  class OpenSSLUtils {
   public:
    /*
     * Get the TLS Session Master Key used to generate the TLS key material
     *
     * @param session ssl session
     * @param keyOut destination for the master key, the buffer must be at least
     * 48 bytes
     * @return true if the master key is available (>= TLS1) and the output buffer
     * large enough
     */
    static bool getTLSMasterKey(
        const SSL_SESSION* session,
        MutableByteRange keyOut);
  
    /*
     * Get the TLS Client Random used to generate the TLS key material
     *
     * @param ssl
     * @param randomOut destination for the client random, the buffer must be at
     * least 32 bytes
     * @return true if the client random is available (>= TLS1) and the output
     * buffer large enough
     */
    static bool getTLSClientRandom(const SSL* ssl, MutableByteRange randomOut);
  
    /**
     * 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.
     *
     * @param cert    X509* peer certificate
     * @param addr    sockaddr object containing sockaddr to verify
     * @param addrLen length of sockaddr as returned by getpeername or accept
     * @return true iff a subject altname IP matches addr
     */
    // TODO(agartrell): Add support for things like common name when
    // necessary.
    static bool
    validatePeerCertNames(X509* cert, const sockaddr* addr, socklen_t addrLen);
  
    /**
     * 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.
     *
     * @param ctx         Context from which to retrieve peer sockaddr
     * @param addrStorage out param for address
     * @param addrLen     out param for length of address
     * @return true on success, false on failure
     */
    static bool getPeerAddressFromX509StoreCtx(
        X509_STORE_CTX* ctx,
        sockaddr_storage* addrStorage,
        socklen_t* addrLen);
  
    /**
     * 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
     *
     * @param cipherCode      A 16-bit IANA cipher code (machine endianness)
     * @return Cipher name, or empty if the code is not found
     */
    static const std::string& getCipherName(uint16_t cipherCode);
  
    /**
     * 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.
     *
     * @param ssl      SSL pointer
     * @param ctx      SSL_CTX pointer
     * @return Cipher name, or empty if the code is not found
     */
    static void setSSLInitialCtx(SSL* ssl, SSL_CTX* ctx);
    static SSL_CTX* getSSLInitialCtx(SSL* ssl);
  
    /**
     * Wrappers for BIO operations that may be different across different
     * versions/flavors of OpenSSL (including forks like BoringSSL)
     */
    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);
  };
  
  } // namespace ssl
  } // namespace folly
  