SSLContext::ServerNameCallbackResult
SSLContextManager::serverNameCallback(SSL* ssl) {
  shared_ptr<SSLContext> ctx;

  const char* sn = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
  if (!sn) {
    VLOG(6) << "Server Name (tlsext_hostname) is missing";
    if (clientHelloTLSExtStats_) {
      clientHelloTLSExtStats_->recordAbsentHostname();
    }
    return SSLContext::SERVER_NAME_NOT_FOUND;
  }
  size_t snLen = strlen(sn);
  VLOG(6) << "Server Name (SNI TLS extension): '" << sn << "' ";

  // FIXME: This code breaks the abstraction. Suggestion?
  AsyncSSLSocket* sslSocket = AsyncSSLSocket::getFromSSL(ssl);
  CHECK(sslSocket);

  DNString dnstr(sn, snLen);

  uint32_t count = 0;
  do {
    // Try exact match first
    ctx = getSSLCtx(dnstr);
    if (ctx) {
      sslSocket->switchServerSSLContext(ctx);
      if (clientHelloTLSExtStats_) {
        clientHelloTLSExtStats_->recordMatch();
      }
      return SSLContext::SERVER_NAME_FOUND;
    }

    ctx = getSSLCtxBySuffix(dnstr);
    if (ctx) {
      sslSocket->switchServerSSLContext(ctx);
      if (clientHelloTLSExtStats_) {
        clientHelloTLSExtStats_->recordMatch();
      }
      return SSLContext::SERVER_NAME_FOUND;
    }

    // Give the noMatchFn one chance to add the correct cert
  }
  while (count++ == 0 && noMatchFn_ && noMatchFn_(sn));

  VLOG(6) << folly::stringPrintf("Cannot find a SSL_CTX for \"%s\"", sn);

  if (clientHelloTLSExtStats_) {
    clientHelloTLSExtStats_->recordNotMatch();
  }
  return SSLContext::SERVER_NAME_NOT_FOUND;
}
示例#2
0
void CurlClient::sslHandshakeFollowup(HTTPUpstreamSession* session) noexcept {
  AsyncSSLSocket* sslSocket = dynamic_cast<AsyncSSLSocket*>(
    session->getTransport());

  const unsigned char* nextProto = nullptr;
  unsigned nextProtoLength = 0;
  sslSocket->getSelectedNextProtocol(&nextProto, &nextProtoLength);
  if (nextProto) {
    VLOG(1) << "Client selected next protocol " <<
      string((const char*)nextProto, nextProtoLength);
  } else {
    VLOG(1) << "Client did not select a next protocol";
  }

  // Note: This ssl session can be used by defining a member and setting
  // something like sslSession_ = sslSocket->getSSLSession() and then
  // passing it to the connector::connectSSL() method
}
示例#3
0
void HTTPConnector::connectSuccess() noexcept {
  if (!cb_) {
    return;
  }

  folly::SocketAddress localAddress;
  folly::SocketAddress peerAddress;
  socket_->getLocalAddress(&localAddress);
  socket_->getPeerAddress(&peerAddress);

  std::unique_ptr<HTTPCodec> codec;

  transportInfo_.acceptTime = getCurrentTime();
  if (transportInfo_.ssl) {
    AsyncSSLSocket* sslSocket = dynamic_cast<AsyncSSLSocket*>(socket_.get());

    const char* npnProto;
    unsigned npnProtoLen;
    sslSocket->getSelectedNextProtocol(
      reinterpret_cast<const unsigned char**>(&npnProto), &npnProtoLen);

    transportInfo_.sslNextProtocol =
        std::make_shared<std::string>(npnProto, npnProtoLen);
    transportInfo_.sslSetupTime = millisecondsSince(connectStart_);
    transportInfo_.sslCipher = sslSocket->getNegotiatedCipherName() ?
      std::make_shared<std::string>(sslSocket->getNegotiatedCipherName()) :
      nullptr;
    transportInfo_.sslVersion = sslSocket->getSSLVersion();
    transportInfo_.sslResume = wangle::SSLUtil::getResumeState(sslSocket);

    codec = makeCodec(*transportInfo_.sslNextProtocol, forceHTTP1xCodecTo1_1_);
  } else {
    codec = makeCodec(plaintextProtocol_, forceHTTP1xCodecTo1_1_);
  }

  HTTPUpstreamSession* session = new HTTPUpstreamSession(
    timeoutSet_,
    std::move(socket_), localAddress, peerAddress,
    std::move(codec), transportInfo_, nullptr);

  cb_->connectSuccess(session);
}
示例#4
0
void HTTPConnector::connectSuccess() noexcept {
  if (!cb_) {
    return;
  }

  folly::SocketAddress localAddress;
  folly::SocketAddress peerAddress;
  socket_->getLocalAddress(&localAddress);
  socket_->getPeerAddress(&peerAddress);

  std::unique_ptr<HTTPCodec> codec;

  transportInfo_.acceptTime = getCurrentTime();
  if (transportInfo_.secure) {
    AsyncSSLSocket* sslSocket = socket_->getUnderlyingTransport<AsyncSSLSocket>();

    if (sslSocket) {
      transportInfo_.sslNextProtocol =
          std::make_shared<std::string>(socket_->getApplicationProtocol());
      transportInfo_.sslSetupTime = millisecondsSince(connectStart_);
      transportInfo_.sslCipher = sslSocket->getNegotiatedCipherName() ?
        std::make_shared<std::string>(sslSocket->getNegotiatedCipherName()) :
        nullptr;
      transportInfo_.sslVersion = sslSocket->getSSLVersion();
      transportInfo_.sslResume = wangle::SSLUtil::getResumeState(sslSocket);
    }

    codec = makeCodec(socket_->getApplicationProtocol(), forceHTTP1xCodecTo1_1_);
  } else {
    codec = makeCodec(plaintextProtocol_, forceHTTP1xCodecTo1_1_);
  }

  HTTPUpstreamSession* session = new HTTPUpstreamSession(
    timeout_,
    std::move(socket_), localAddress, peerAddress,
    std::move(codec), transportInfo_, nullptr);

  cb_->connectSuccess(session);
}
SSL_SESSION* SSLSessionCacheManager::getSession(SSL* ssl,
        unsigned char* session_id,
        int id_len,
        int* copyflag) {
    VLOG(7) << "SSL get session callback";
    SSL_SESSION* session = nullptr;
    bool foreign = false;
    char const* missReason = nullptr;

    if (id_len < MIN_SESSION_ID_LENGTH) {
        // We didn't generate this session so it's going to be a miss.
        // This doesn't get logged or counted in the stats.
        return nullptr;
    }
    string sessionId((char*)session_id, id_len);

    AsyncSSLSocket* sslSocket = AsyncSSLSocket::getFromSSL(ssl);

    assert(sslSocket != nullptr);

    // look it up in the local cache first
    session = localCache_->lookupSession(sessionId);
#ifdef SSL_SESSION_CB_WOULD_BLOCK
    if (session == nullptr && externalCache_) {
        // external cache might have the session
        foreign = true;
        if (!SSL_want_sess_cache_lookup(ssl)) {
            missReason = "reason: No async cache support;";
        } else {
            PendingLookupMap::iterator pit = pendingLookups_.find(sessionId);
            if (pit == pendingLookups_.end()) {
                auto result = pendingLookups_.emplace(sessionId, PendingLookup());
                // initiate fetch
                VLOG(4) << "Get SSL session [Pending]: Initiate Fetch; fd=" <<
                        sslSocket->getFd() << " id=" << SSLUtil::hexlify(sessionId);
                if (lookupCacheRecord(sessionId, sslSocket)) {
                    // response is pending
                    *copyflag = SSL_SESSION_CB_WOULD_BLOCK;
                    return nullptr;
                } else {
                    missReason = "reason: failed to send lookup request;";
                    pendingLookups_.erase(result.first);
                }
            } else {
                // A lookup was already initiated from this thread
                if (pit->second.request_in_progress) {
                    // Someone else initiated the request, attach
                    VLOG(4) << "Get SSL session [Pending]: Request in progess: attach; "
                            "fd=" << sslSocket->getFd() << " id=" <<
                            SSLUtil::hexlify(sessionId);
                    std::unique_ptr<DelayedDestruction::DestructorGuard> dg(
                        new DelayedDestruction::DestructorGuard(sslSocket));
                    pit->second.waiters.emplace_back(sslSocket, std::move(dg));
                    *copyflag = SSL_SESSION_CB_WOULD_BLOCK;
                    return nullptr;
                }
                // request is complete
                session = pit->second.session; // nullptr if our friend didn't have it
                if (session != nullptr) {
                    CRYPTO_add(&session->references, 1, CRYPTO_LOCK_SSL_SESSION);
                }
            }
        }
    }
#endif

    bool hit = (session != nullptr);
    if (stats_) {
        stats_->recordSSLSession(false, hit, foreign);
    }
    if (hit) {
        sslSocket->setSessionIDResumed(true);
    }

    VLOG(4) << "Get SSL session [" <<
            ((hit) ? "Hit" : "Miss") << "]: " <<
            ((foreign) ? "external" : "local") << " cache; " <<
            ((missReason != nullptr) ? missReason : "") << "fd=" <<
            sslSocket->getFd() << " id=" << SSLUtil::hexlify(sessionId);

    // We already bumped the refcount
    *copyflag = 0;

    return session;
}
示例#6
0
void
AsyncSSLSocket::clientHelloParsingCallback(int written, int version,
    int contentType, const void *buf, size_t len, SSL *ssl, void *arg)
{
  AsyncSSLSocket *sock = static_cast<AsyncSSLSocket*>(arg);
  if (written != 0) {
    sock->resetClientHelloParsing(ssl);
    return;
  }
  if (contentType != SSL3_RT_HANDSHAKE) {
    sock->resetClientHelloParsing(ssl);
    return;
  }
  if (len == 0) {
    return;
  }

  auto& clientHelloBuf = sock->clientHelloInfo_->clientHelloBuf_;
  clientHelloBuf.append(IOBuf::wrapBuffer(buf, len));
  try {
    Cursor cursor(clientHelloBuf.front());
    if (cursor.read<uint8_t>() != SSL3_MT_CLIENT_HELLO) {
      sock->resetClientHelloParsing(ssl);
      return;
    }

    if (cursor.totalLength() < 3) {
      clientHelloBuf.trimEnd(len);
      clientHelloBuf.append(IOBuf::copyBuffer(buf, len));
      return;
    }

    uint32_t messageLength = cursor.read<uint8_t>();
    messageLength <<= 8;
    messageLength |= cursor.read<uint8_t>();
    messageLength <<= 8;
    messageLength |= cursor.read<uint8_t>();
    if (cursor.totalLength() < messageLength) {
      clientHelloBuf.trimEnd(len);
      clientHelloBuf.append(IOBuf::copyBuffer(buf, len));
      return;
    }

    sock->clientHelloInfo_->clientHelloMajorVersion_ = cursor.read<uint8_t>();
    sock->clientHelloInfo_->clientHelloMinorVersion_ = cursor.read<uint8_t>();

    cursor.skip(4); // gmt_unix_time
    cursor.skip(28); // random_bytes

    cursor.skip(cursor.read<uint8_t>()); // session_id

    uint16_t cipherSuitesLength = cursor.readBE<uint16_t>();
    for (int i = 0; i < cipherSuitesLength; i += 2) {
      sock->clientHelloInfo_->
        clientHelloCipherSuites_.push_back(cursor.readBE<uint16_t>());
    }

    uint8_t compressionMethodsLength = cursor.read<uint8_t>();
    for (int i = 0; i < compressionMethodsLength; ++i) {
      sock->clientHelloInfo_->
        clientHelloCompressionMethods_.push_back(cursor.readBE<uint8_t>());
    }

    if (cursor.totalLength() > 0) {
      uint16_t extensionsLength = cursor.readBE<uint16_t>();
      while (extensionsLength) {
        sock->clientHelloInfo_->
          clientHelloExtensions_.push_back(cursor.readBE<uint16_t>());
        extensionsLength -= 2;
        uint16_t extensionDataLength = cursor.readBE<uint16_t>();
        extensionsLength -= 2;
        cursor.skip(extensionDataLength);
        extensionsLength -= extensionDataLength;
      }
    }
  } catch (std::out_of_range& e) {
    // we'll use what we found and cleanup below.
    VLOG(4) << "AsyncSSLSocket::clientHelloParsingCallback(): "
      << "buffer finished unexpectedly." << " AsyncSSLSocket socket=" << sock;
  }

  sock->resetClientHelloParsing(ssl);
}