From: Christos Tsantilas Date: Tue, 6 May 2014 09:46:07 +0000 (+0300) Subject: ssl_bump_peeked access list X-Git-Tag: SQUID_3_5_0_1~89^2~19 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7f4e9b738eb322fdbbd8e3d4fd38d8f8fafd449f;p=thirdparty%2Fsquid.git ssl_bump_peeked access list This access list is a temporary solution for peek-and-splice project and used to take the final decision "bump" or "splice" in peek-and-splice bumping mode. This is what this patch try to do: - Get Client Hello message - Start connection. - Inside bio, before write the SSL HELLO message, try to emulate client hello message: a) extract client hello message features b) Check if we are able support client features and if not, splicing is not able to be supported. c) Creates an SSL object to connect to server and try to set it with the extracted features. This step currently includes many hacks and modify undocumented SSL object members. extensions) - in PeerConnector.cc a) If can not be spliced do not splice. b) check the ssl_bump_peeked access list to splice or not. --- diff --git a/src/SquidConfig.h b/src/SquidConfig.h index 97d09a3100..30a6d53f10 100644 --- a/src/SquidConfig.h +++ b/src/SquidConfig.h @@ -390,6 +390,7 @@ public: #if USE_OPENSSL acl_access *ssl_bump; + acl_access *ssl_bump_peeked; #endif #if FOLLOW_X_FORWARDED_FOR acl_access *followXFF; diff --git a/src/cache_cf.cc b/src/cache_cf.cc index 6ca7b61248..dd70b946db 100644 --- a/src/cache_cf.cc +++ b/src/cache_cf.cc @@ -242,6 +242,10 @@ static void free_sslproxy_cert_adapt(sslproxy_cert_adapt **cert_adapt); static void parse_sslproxy_ssl_bump(acl_access **ssl_bump); static void dump_sslproxy_ssl_bump(StoreEntry *entry, const char *name, acl_access *ssl_bump); static void free_sslproxy_ssl_bump(acl_access **ssl_bump); + +static void parse_sslproxy_ssl_bump_peeked(acl_access **ssl_bump); +static void dump_sslproxy_ssl_bump_peeked(StoreEntry *entry, const char *name, acl_access *ssl_bump); +static void free_sslproxy_ssl_bump_peeked(acl_access **ssl_bump); #endif /* USE_OPENSSL */ static void parse_ftp_epsv(acl_access **ftp_epsv); @@ -4729,6 +4733,53 @@ static void free_sslproxy_ssl_bump(acl_access **ssl_bump) free_acl_access(ssl_bump); } +static void +parse_sslproxy_ssl_bump_peeked(acl_access **ssl_bump_peeked) +{ + char *bm; + if ((bm = ConfigParser::NextToken()) == NULL) { + self_destruct(); + return; + } + + allow_t action = allow_t(ACCESS_ALLOWED); + + if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpServerFirst]) == 0) { + action.kind = Ssl::bumpServerFirst; + } else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpSplice]) == 0) { + action.kind = Ssl::bumpSplice; + } else { + debugs(3, DBG_CRITICAL, "FATAL: unknown ssl_bump_peeked mode: " << bm); + self_destruct(); + return; + } + + Acl::AndNode *rule = new Acl::AndNode; + rule->context("(ssl_bump_peeked rule)", config_input_line); + rule->lineParse(); + + assert(ssl_bump_peeked); + if (!*ssl_bump_peeked) { + *ssl_bump_peeked = new Acl::Tree; + (*ssl_bump_peeked)->context("(ssl_bump_peeked rules)", config_input_line); + } + + (*ssl_bump_peeked)->add(rule, action); +} + +static void +dump_sslproxy_ssl_bump_peeked(StoreEntry *entry, const char *name, acl_access *ssl_bump_peeked) +{ + if (ssl_bump_peeked) + dump_SBufList(entry, ssl_bump_peeked->treeDump(name, Ssl::BumpModeStr)); +} + +static void +free_sslproxy_ssl_bump_peeked(acl_access **ssl_bump_peeked) +{ + free_acl_access(ssl_bump_peeked); +} + #endif static void dump_HeaderWithAclList(StoreEntry * entry, const char *name, HeaderWithAclList *headers) diff --git a/src/cf.data.depend b/src/cf.data.depend index 4776fd6bad..52b4aa7edd 100644 --- a/src/cf.data.depend +++ b/src/cf.data.depend @@ -73,6 +73,7 @@ wccp2_service wccp2_service_info wordlist sslproxy_ssl_bump acl +sslproxy_ssl_bump_peeked acl sslproxy_cert_sign acl sslproxy_cert_adapt acl ftp_epsv acl diff --git a/src/cf.data.pre b/src/cf.data.pre index a99011006d..191c5fe319 100644 --- a/src/cf.data.pre +++ b/src/cf.data.pre @@ -2491,6 +2491,29 @@ DOC_START ssl_bump server-first all DOC_END +NAME: ssl_bump_peeked +IFDEF: USE_OPENSSL +TYPE: sslproxy_ssl_bump_peeked +LOC: Config.accessList.ssl_bump_peeked +DEFAULT: none +DOC_START + This option used to control splicing decision after we peek at the + certificates + + ssl_bump_peeked [!]acl ... + + The following peeked modes are supported: + + server-first + Allow bumping the connection + + splice + Do not bump the connection if possible. + + ssl_bump_peeked server-first safeToBump + ssl_bump_peeked splice all +DOC_END + NAME: sslproxy_flags IFDEF: USE_OPENSSL DEFAULT: none diff --git a/src/ssl/PeerConnector.cc b/src/ssl/PeerConnector.cc index 01e6332401..8103198774 100644 --- a/src/ssl/PeerConnector.cc +++ b/src/ssl/PeerConnector.cc @@ -14,6 +14,7 @@ #include "globals.h" #include "HttpRequest.h" #include "neighbors.h" +#include "SquidConfig.h" #include "ssl/bio.h" #include "ssl/cert_validate_message.h" #include "ssl/Config.h" @@ -153,7 +154,7 @@ Ssl::PeerConnector::initializeSsl() if (features.sslVersion >= 3) { b = SSL_get_rbio(ssl); Ssl::ServerBio *srvBio = static_cast(b->ptr); - srvBio->setClientRandom(features.client_random); + srvBio->setClientFeatures(features); srvBio->recordInput(true); } } @@ -265,24 +266,45 @@ Ssl::PeerConnector::negotiateSsl() } void switchToTunnel(HttpRequest *request, int *status_ptr, Comm::ConnectionPointer & clientConn, Comm::ConnectionPointer &srvConn); + void -Ssl::PeerConnector::checkForPeekAndSplice() +Ssl::PeerConnector::cbCheckForPeekAndSplice(allow_t answer, void *data) +{ + Ssl::PeerConnector *peerConnect = (Ssl::PeerConnector *) data; + peerConnect->checkForPeekAndSplice(true, (Ssl::BumpMode)answer.kind); +} + +bool +Ssl::PeerConnector::checkForPeekAndSplice(bool checkDone, Ssl::BumpMode peekMode) { SSL *ssl = fd_table[serverConn->fd].ssl; BIO *b = SSL_get_rbio(ssl); Ssl::ServerBio *srvBio = static_cast(b->ptr); debugs(83,5, "Will check for peek and splice on fd " << serverConn->fd); - const bool splice = true; + bool splice; + if (!srvBio->canSplice()) + splice = false; + else if (!checkDone) { + ACLFilledChecklist *acl_checklist = new ACLFilledChecklist( + ::Config.accessList.ssl_bump_peeked, + request.getRaw(), NULL); + acl_checklist->nonBlockingCheck(Ssl::PeerConnector::cbCheckForPeekAndSplice, this); + return false; + } else + splice = (peekMode == Ssl::bumpSplice); + if (!splice) { //Allow write, proceed with the connection srvBio->holdWrite(false); srvBio->recordInput(false); Comm::SetSelect(serverConn->fd, COMM_SELECT_WRITE, &NegotiateSsl, this, 0); debugs(83,5, "Retry the fwdNegotiateSSL on fd " << serverConn->fd); + return true; } else { static int status_code = 0; debugs(83,5, "Revert to tunnel fd " << clientConn->fd << " with fd " << serverConn->fd); switchToTunnel(request.getRaw(), &status_code, clientConn, serverConn); + return false; } } @@ -435,7 +457,7 @@ Ssl::PeerConnector::handleNegotiateError(const int ret) case SSL_ERROR_WANT_WRITE: if (request->clientConnectionManager->sslBumpMode == Ssl::bumpPeekAndSplice && srvBio->holdWrite()) { debugs(81, DBG_IMPORTANT, "hold write on SSL connection on FD " << fd); - checkForPeekAndSplice(); + checkForPeekAndSplice(false, Ssl::bumpNone); return; } Comm::SetSelect(fd, COMM_SELECT_WRITE, &NegotiateSsl, this, 0); @@ -445,6 +467,19 @@ Ssl::PeerConnector::handleNegotiateError(const int ret) case SSL_ERROR_SYSCALL: ssl_lib_error = ERR_get_error(); + // If we are in peek-and-splice mode and still we did not write to + // server yet, try to see if we should splice. + // In this case the connection can be saved. + // If the checklist decision is do not splice a new error will + // occure in the next SSL_connect call, and we will fail again. +#if 1 + if (request->clientConnectionManager->sslBumpMode == Ssl::bumpPeekAndSplice && srvBio->holdWrite()) { + debugs(81, DBG_IMPORTANT, "fwdNegotiateSSL: Error but, hold write on SSL connection on FD " << fd); + checkForPeekAndSplice(false, Ssl::bumpNone); + return; + } +#endif + // store/report errno when ssl_error is SSL_ERROR_SYSCALL, ssl_lib_error is 0, and ret is -1 if (ssl_error == SSL_ERROR_SYSCALL && ret == -1 && ssl_lib_error == 0) sysErrNo = errno; diff --git a/src/ssl/PeerConnector.h b/src/ssl/PeerConnector.h index 8ab4b702ab..73c7b27135 100644 --- a/src/ssl/PeerConnector.h +++ b/src/ssl/PeerConnector.h @@ -125,7 +125,7 @@ protected: /// It is called multiple times untill the negotiation finish or aborted. void negotiateSsl(); - void checkForPeekAndSplice(); + bool checkForPeekAndSplice(bool, Ssl::BumpMode); /// Called when the SSL negotiation step aborted because data needs to /// be transferred to/from SSL server or on error. In the first case @@ -158,6 +158,9 @@ private: /// A wrapper function for negotiateSsl for use with Comm::SetSelect static void NegotiateSsl(int fd, void *data); + /// A wrapper function for checkForPeekAndSplice for use with acl + static void cbCheckForPeekAndSplice(allow_t answer, void *data); + HttpRequestPointer request; ///< peer connection trigger or cause Comm::ConnectionPointer serverConn; ///< TCP connection to the peer Comm::ConnectionPointer clientConn; ///< TCP connection to the client diff --git a/src/ssl/bio.cc b/src/ssl/bio.cc index 9ec0bc9501..80039d018f 100644 --- a/src/ssl/bio.cc +++ b/src/ssl/bio.cc @@ -193,7 +193,7 @@ Ssl::ClientBio::read(char *buf, int size, BIO *table) if (headerState < 2) { if (rbuf.isNull()) - rbuf.init(1024, 4096); + rbuf.init(1024, 16384); size = rbuf.spaceSize() > size ? size : rbuf.spaceSize(); @@ -221,10 +221,12 @@ Ssl::ClientBio::read(char *buf, int size, BIO *table) debugs(83, 7, "SSL version 3 handshake message"); headerBytes = (head[3] << 8) + head[4]; debugs(83, 7, "SSL Header Size: " << headerBytes); + headerBytes +=5; #ifdef DO_SSLV23 } else if ((head[0] & 0x80) && head[2] == 0x01 && head[3] == 0x03) { debugs(83, 7, "SSL version 2 handshake message with v3 support"); headerBytes = head[1]; + headerBytes +=5; #endif }else { debugs(83, 7, "Not an SSL acceptable handshake message (SSLv2 message?)"); @@ -273,10 +275,19 @@ Ssl::ServerBio::stateChanged(const SSL *ssl, int where, int ret) } void -Ssl::ServerBio::setClientRandom(const unsigned char *r) +Ssl::ServerBio::setClientFeatures(const Ssl::Bio::sslFeatures &features) { - memcpy(clientRandom, r, SSL3_RANDOM_SIZE); - randomSet = true; + clientFeatures.sslVersion = features.sslVersion; + clientFeatures.compressMethod = features.compressMethod; + clientFeatures.serverName = features.serverName; + clientFeatures.clientRequestedCiphers = features.clientRequestedCiphers; + clientFeatures.unknownCiphers = features.unknownCiphers; + memcpy(clientFeatures.client_random, features.client_random, SSL3_RANDOM_SIZE); + clientFeatures.helloMessage.init(features.helloMessage.contentSize(), features.helloMessage.contentSize()); + clientFeatures.helloMessage.append(features.helloMessage.content(), features.helloMessage.contentSize()); + clientFeatures.doHeartBeats = features.doHeartBeats; + clientFeatures.extensions = features.extensions; + featuresSet = true; }; int @@ -286,56 +297,167 @@ Ssl::ServerBio::read(char *buf, int size, BIO *table) if (bytes > 0 && record_) { if (rbuf.isNull()) - rbuf.init(1024, 8196); + rbuf.init(1024, 16384); rbuf.append(buf, bytes); + debugs(83, 5, "Record is enabled store " << bytes << " bytes"); } + debugs(83, 5, "Read " << bytes << " from " << size << " bytes"); return bytes; } +bool +adjustSSL(SSL *ssl, Ssl::Bio::sslFeatures &features) +{ + // If the client supports compression but our context does not support + // we can not adjust. + if (features.compressMethod && ssl->ctx->comp_methods == NULL) { + debugs(83, 5, "Client Hello Data supports compression, but we do not!"); + return false; + } + + //Check ciphers list + size_t token = 0; + size_t end = 0; + while (token != std::string::npos) { + end = features.clientRequestedCiphers.find(':',token); + std::string cipher; + cipher.assign(features.clientRequestedCiphers, token, end - token); + token = (end != std::string::npos ? end + 1 : std::string::npos); + bool found = false; + STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(ssl); + for (int i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++) { + SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i); + const char *cname = SSL_CIPHER_get_name(c); + if (cipher.compare(cname)) { + found = true; + break; + } + } + if (!found) { + debugs(83, 5, "Client Hello Data supports cipher '"<< cipher <<"' but we do not support it!"); + return false; + } + } + +#if !defined(SSL_TLSEXT_HB_ENABLED) + if (features.doHeartBeats) { + debugs(83, 5, "Client Hello Data supports HeartBeats but we do not support!"); + return false; + } +#endif + + for (std::list::iterator it = features.extensions.begin(); it != features.extensions.end(); ++it) { + static int supportedExtensions[] = { + TLSEXT_TYPE_server_name, +#ifdef TLSEXT_TYPE_opaque_prf_input + TLSEXT_TYPE_opaque_prf_input, +#endif +#ifdef TLSEXT_TYPE_heartbeat + TLSEXT_TYPE_heartbeat, +#endif +#ifdef TLSEXT_TYPE_renegotiate + TLSEXT_TYPE_renegotiate, +#endif +#ifdef TLSEXT_TYPE_ec_point_formats + TLSEXT_TYPE_ec_point_formats, +#endif +#ifdef TLSEXT_TYPE_elliptic_curves + TLSEXT_TYPE_elliptic_curves, +#endif +#ifdef TLSEXT_TYPE_session_ticket + TLSEXT_TYPE_session_ticket, +#endif +#ifdef TLSEXT_TYPE_status_request + TLSEXT_TYPE_status_request, +#endif +#ifdef TLSEXT_TYPE_use_srtp + TLSEXT_TYPE_use_srtp, +#endif +#if 1 //Allow 13172 Firefox supported extension for testing purposes + 13172, +#endif + -1 + }; + bool found = false; + for (int i = 0; supportedExtensions[i] != -1; i++) { + if (*it == supportedExtensions[i]) { + found = true; + break; + } + } + if (!found) { + debugs(83, 5, "Extension " << *it << " does not supported!"); + return false; + } + } + + + debugs(83, 5, "Hello Data are OK and can be mimicked!"); + + //Adjust ssl structure data. + + // We need to fix the random in SSL struct: + memcpy(ssl->s3->client_random, features.client_random, SSL3_RANDOM_SIZE); + + SSL3_BUFFER *wb=&(ssl->s3->wbuf); + assert(wb->len > (size_t)features.helloMessage.contentSize()); + memcpy(wb->buf, features.helloMessage.content(), features.helloMessage.contentSize()); + wb->left = features.helloMessage.contentSize(); + + size_t mainHelloSize = features.helloMessage.contentSize() - 5; + const char *mainHello = features.helloMessage.content() + 5; + assert(ssl->init_buf->max > mainHelloSize); + memcpy(ssl->init_buf->data, mainHello, mainHelloSize); + debugs(83, 5, "Hello Data init and adjustd sizes :" << ssl->init_num << " = "<< mainHelloSize); + ssl->init_num = mainHelloSize; + ssl->s3->wpend_ret = mainHelloSize; + ssl->s3->wpend_tot = mainHelloSize; + return true; +} + int Ssl::ServerBio::write(const char *buf, int size, BIO *table) { if (holdWrite_) { - debugs(83, 7, "Hold write, for SSL connection on " << fd_); + debugs(83, 7, "Hold write, for SSL connection on " << fd_ << "will not write bytes of size " << size); BIO_set_retry_write(table); return -1; } if (!helloBuild) { + if (helloMsg.isNull()) + helloMsg.init(1024, 16384); + if ( buf[1] >= 3 //it is an SSL Version3 message && buf[0] == 0x16 // and it is a Handshake/Hello message ) { - if (helloMsg.isNull()) - helloMsg.init(1024, 4096); //Hello message is the first message we write to server assert(!helloMsg.hasContent()); SSL *ssl = fd_table[fd_].ssl; - if (randomSet && ssl && ssl->s3) { - assert(size > 11 + SSL3_RANDOM_SIZE); - helloMsg.append(buf, 11); - //The random number is stored in the 11 position of the - // message we are going to sent - helloMsg.append((char *)clientRandom, SSL3_RANDOM_SIZE); - size_t len = size - 11 - SSL3_RANDOM_SIZE; - helloMsg.append(buf + 11 + SSL3_RANDOM_SIZE, len); - - // We need to fix the random in SSL struct: - memcpy(ssl->s3->client_random, clientRandom, SSL3_RANDOM_SIZE); - // We also need to fix the raw message in SSL struct - // stored in SSL->init_buf. Looks that it is used to get - // digest of the previous sent SSL message, to compute keys - // for encryption/decryption: - memcpy(ssl->init_buf->data + 6, clientRandom, SSL3_RANDOM_SIZE); - - debugs(83, 7, "SSL HELLO message for FD " << fd_ << ": Random number is adjusted"); + if (featuresSet && ssl && ssl->s3) { + if (adjustSSL(ssl, clientFeatures)) { + allowSplice = true; + helloMsg.append(clientFeatures.helloMessage.content(), clientFeatures.helloMessage.contentSize()); + debugs(83, 7, "SSL HELLO message for FD " << fd_ << ": Random number is adjusted"); + } } } + // If we do not build any hello message, copy the current + if (!helloMsg.hasContent()) + helloMsg.append(buf, size); + helloBuild = true; helloMsgSize = helloMsg.contentSize(); + + if (allowSplice) { + // Do not write yet..... + BIO_set_retry_write(table); + return -1; + } } if (helloMsg.hasContent()) { @@ -350,9 +472,10 @@ Ssl::ServerBio::write(const char *buf, int size, BIO *table) } // Sending hello message complete. Do not send more data for now... - holdWrite_ = true; + holdWrite_ = true; + // The size should be less than the size of the hello message - assert(size >= helloMsgSize); + //assert(size >= helloMsgSize); return helloMsgSize; } else return Ssl::Bio::write(buf, size, table); @@ -486,7 +609,7 @@ squid_ssl_info(const SSL *ssl, int where, int ret) } } -Ssl::Bio::sslFeatures::sslFeatures(): sslVersion(-1), compressMethod(-1) +Ssl::Bio::sslFeatures::sslFeatures(): sslVersion(-1), compressMethod(-1), unknownCiphers(false), doHeartBeats(true) { memset(client_random, 0, SSL3_RANDOM_SIZE); } @@ -621,6 +744,8 @@ Ssl::Bio::sslFeatures::parseV3Hello(const unsigned char *hello) // The following hello message size exist in 4th and 5th bytes int helloSize = (hello[3] << 8) | hello[4]; helloSize += 5; //Include the 5 header bytes. + helloMessage.init(helloSize, helloSize); + helloMessage.append((const char *)hello, helloSize); //For SSLv3 or TLSv1.* protocols we can get some more informations if (hello[1] == 0x3 && hello[5] == 0x1 /*HELLO A message*/) { @@ -648,7 +773,8 @@ Ssl::Bio::sslFeatures::parseV3Hello(const unsigned char *hello) if(!clientRequestedCiphers.empty()) clientRequestedCiphers.append(":"); clientRequestedCiphers.append(c->name); - } + } else + unknownCiphers = true; } } debugs(83, 7, "Ciphers requested by client: " << clientRequestedCiphers); @@ -662,11 +788,11 @@ Ssl::Bio::sslFeatures::parseV3Hello(const unsigned char *hello) compressMethod = 0; debugs(83, 7, "SSL compression methods number: " << (int)compression[0]); - const unsigned char *extensions = compression + 1 + (int)compression[0]; - if (extensions < hello + helloSize) { - int extensionsLen = (extensions[0] << 8) | extensions[1]; - const unsigned char *ext = extensions + 2; - while (ext < extensions+extensionsLen){ + const unsigned char *pToExtensions = compression + 1 + (int)compression[0]; + if (pToExtensions < hello + helloSize) { + int extensionsLen = (pToExtensions[0] << 8) | pToExtensions[1]; + const unsigned char *ext = pToExtensions + 2; + while (ext < pToExtensions + extensionsLen){ short extType = (ext[0] << 8) | ext[1]; ext += 2; short extLen = (ext[0] << 8) | ext[1]; @@ -680,7 +806,12 @@ Ssl::Bio::sslFeatures::parseV3Hello(const unsigned char *hello) int hostLen = (ext[3] << 8) | ext[4]; serverName.assign((const char *)(ext+5), hostLen); debugs(83, 7, "Found server name: " << serverName); - } + } else if (extType == 15 && ext[0] != 0) { + // The heartBeats are the type 15 + doHeartBeats = true; + } else + extensions.push_back(extType); + ext += extLen; } } @@ -699,6 +830,8 @@ Ssl::Bio::sslFeatures::parseV23Hello(const unsigned char *hello) // The following hello message size exist in 2nd byte int helloSize = hello[1]; helloSize += 2; //Include the 2 header bytes. + helloMessage.init(helloSize, helloSize); + helloMessage.append((char *)hello, helloSize); //Ciphers list. It is stored after the Session ID. diff --git a/src/ssl/bio.h b/src/ssl/bio.h index 690a6ab099..eb8f08cd85 100644 --- a/src/ssl/bio.h +++ b/src/ssl/bio.h @@ -3,6 +3,7 @@ #include "MemBuf.h" #include +#include #if HAVE_OPENSSL_BIO_H #include #endif @@ -37,11 +38,15 @@ public: int compressMethod; ///< The requested/used compressed method std::string serverName; ///< The SNI hostname, if any std::string clientRequestedCiphers; ///< The client requested ciphers + bool unknownCiphers; ///< True if one or more ciphers are unknown std::string ecPointFormatList;///< tlsExtension ecPointFormatList std::string ellipticCurves; ///< tlsExtension ellipticCurveList std::string opaquePrf; ///< tlsExtension opaquePrf + bool doHeartBeats; /// The client random number unsigned char client_random[SSL3_RANDOM_SIZE]; + std::list extensions; + MemBuf helloMessage; }; explicit Bio(const int anFd); ~Bio(); @@ -109,7 +114,7 @@ private: /// BIO node to handle socket IO for squid server side class ServerBio: public Bio { public: - explicit ServerBio(const int anFd): Bio(anFd), randomSet(false), helloMsgSize(0), helloBuild(false), holdWrite_(false), record_(false) {} + explicit ServerBio(const int anFd): Bio(anFd), featuresSet(false), helloMsgSize(0), helloBuild(false), allowSplice(false), holdWrite_(false), record_(false) {} /// The ServerBio version of the Ssl::Bio::stateChanged method virtual void stateChanged(const SSL *ssl, int where, int ret); /// The ServerBio version of the Ssl::Bio::write method @@ -124,19 +129,21 @@ public: /// Flushes any buffered data virtual void flush(BIO *table); /// Sets the random number to use in client SSL HELLO message - void setClientRandom(const unsigned char *r); + void setClientFeatures(const sslFeatures &features); bool holdWrite() const {return holdWrite_;} void holdWrite(bool h) {holdWrite_ = h;} void recordInput(bool r) {record_ = r;} const MemBuf &rBufData() {return rbuf;} + bool canSplice() {return allowSplice;} private: /// A random number to use as "client random" in client hello message - unsigned char clientRandom[SSL3_RANDOM_SIZE]; - bool randomSet; ///< True if the clientRandom member is set and can be used + sslFeatures clientFeatures; + bool featuresSet; ///< True if the clientFeatures member is set and can be used MemBuf helloMsg; ///< Used to buffer output data. int helloMsgSize; bool helloBuild; ///< True if the client hello message sent to the server + bool allowSplice; bool holdWrite_; ///< The write hold state of the bio. bool record_; MemBuf rbuf; ///< Used to buffer input data. diff --git a/src/ssl/support.cc b/src/ssl/support.cc index 33566e137a..3954723536 100644 --- a/src/ssl/support.cc +++ b/src/ssl/support.cc @@ -66,6 +66,7 @@ const char *Ssl::BumpModeStr[] = { "client-first", "server-first", "peek-and-splice", + "splice", NULL }; diff --git a/src/ssl/support.h b/src/ssl/support.h index c538411570..45af1afa7f 100644 --- a/src/ssl/support.h +++ b/src/ssl/support.h @@ -158,7 +158,7 @@ GETX509ATTRIBUTE GetX509Fingerprint; \ingroup ServerProtocolSSLAPI * Supported ssl-bump modes */ -enum BumpMode {bumpNone = 0, bumpClientFirst, bumpServerFirst, bumpPeekAndSplice, bumpEnd}; +enum BumpMode {bumpNone = 0, bumpClientFirst, bumpServerFirst, bumpPeekAndSplice, bumpSplice, bumpEnd}; /** \ingroup ServerProtocolSSLAPI