[squid-dev] [PATCH] switch session/connection for OpenSSL

Amos Jeffries squid3 at treenet.co.nz
Sun Jul 9 10:30:35 UTC 2017


On 09/07/17 15:28, Alex Rousskov wrote:
> On 06/10/2017 06:27 AM, Amos Jeffries wrote:
> 
>> Yes this is far from complete, and intentionally much smaller that
>> the previous patch.
> 
> I believe this patch is a huge step in the right direction. It has one
> serious flaw (namespace misuse), but I hope that can be addressed
> without too much controversy. The details are further below.
> 
> 
>> On 27/04/17 05:24, Alex Rousskov wrote:
>>> Needless to say, I would be happy if we can come up with better
>>> definitions or even better concepts. The above is a starting point.
> 
>> I do not think it is up to us to define these things. So I have taken a
>> much longer reading of all the RFCs since SSLv3.0 through to current
>> TLS/1.3 and isolated what are the authoritative definitions AFAICT.
> 
> For the record, I am happy to adopt any "authoritative" definitions that
> suite Squid specifics well, but, IMO, it is up to _us_ to decide
> suitability and, if necessary, to define and/or clarify things within
> Squid context. Quoting RFCs is often useful, but it is not a panacea for
> any problem, including the terminology problem.
> 
> For example, a TLS Connection exists, as a concept, whether any RFC
> defines or not. An RFC may not need that definition, may assume that
> every reader already understands that concept, or may just be sloppy. We
> should reuse what we can and fill the gaps with our own definitions as
> needed.
> 
> 
>> * moves the pieces that are doing what is defined as solely TLS
>> Connection things to security/TlsConnection.* files.
> 
> Please do not misinterpret the namespace comments below as a
> disagreement with the above change. Moving TLS Connection code to
> security/TlsConnection.* files is fine with me.
> 
> 
>> * adds a Security::TlsConnection::Pointer type for use by code dealing
>> with TLS Connection logic.
> 
> This is also great.
> 
> 
>>   - SessionPointer still exists for code performing TLS Session logic.
>> see PeerConnector description for the distinction.
> 
> Sure, this is fine. TLS Session is a perfectly valid concept as well.
> 
> 
>>   - I have not gone through and renamed uses of SessionPointer beyond
>> those directly involved with the above code shuffle.
> 
> Can you give an example or two of old uses that should be fixed? Do you
> plan on doing this renaming as a part of this series of patches? It
> would be nice to get rid of the inconsistencies in one sweep or, if
> necessary, several close-in-time changes...
> 

class fde "ssl" member. This is a pointer to the TLS session state for 
the TCP connection whose FD the fd_table entry is storing.



> 
>> +namespace TlsConnection {
> 
> We should not use namespaces for what is a class. Very roughly speaking:
> If you can create multiple instances of X, then X is (or can be) a
> class. It is not a namespace. In this context:
> 
> * I can have five "TLS connections". A "TLS connection" is (or can be) a
> class.
> 
> * All TLS-related functions, classes, constants, and other interfaces
> can be grouped under a single "Tls" namespace. I cannot have five TLSs.
> "Tls" is (or can be) a namespace.

They might be one day. That is out of scope of this patch which 
concentrates solely on documenting the border between TLS connection and 
TLS session.

> 
> N.B. I do not suggest adding a TLS connection class now (and we already
> have library-specific types that currently fulfill that role,
> essentially). Using Security::ConnectionPointer is enough.

The classes in Squid which most accurately match the "TLS connection" 
definition are actually class fde and class Comm::Connection. Since fde 
stores the FD value, I/O handlers and pointer to an active SSL session 
(indirectly via the SSL* pointer), and Comm::Connection stores the FD 
and related state/session data.


> 
> 
>> +    if (Security::TlsConnection::CreateServer(ctx, conn, "client https start")) {
> 
> I would replace TlsConnection::CreateServer, which reads like nonsense


Take a look at the naming of this code in Squid-3. These are the names 
you have spent most of a year trying to get me to undo. Now you are 
saying they were nonsense.

"
SSL *
Ssl::CreateClient(SSL_CTX *sslContext, const int fd, const char *squidCtx)
{
     return SslCreate(sslContext, fd, Ssl::Bio::BIO_TO_SERVER, squidCtx);
}

SSL *
Ssl::CreateServer(SSL_CTX *sslContext, const int fd, const char *squidCtx)
{
     return SslCreate(sslContext, fd, Ssl::Bio::BIO_TO_CLIENT, squidCtx);
}
"



> IMHO, with something like:
> 
> * Accept
> * AcceptConnection
> * PrepareToAccept
> * CreateConnection(ToSquid)
> 
> And the corresponding names for the Squid-to-peer TLS connections:
> 
> * Connect
> * InitiateConnection
> * PrepareToConnect
> * CreateConnection(FromSquid)
> 
> "Accept" and "connect" are common networking terms that can be applied
> to TLS connections well. The last two versions in each group are more
> precise because these functions only _prepare_ the TLS connection for
> future negotiations; they do not actually start those negotiations.


The CreateX() functions are the constructors of the _data structure_ for 
storing TLS context data. They have zero properties and similarity with 
accept(2) or connect(2) in TCP connections.

*IF* these functions actually did connection semantics then all of the 
logic in the class PeerConnector hierarchy is completely wrong.
  (you may recall that one of the major mistakes I made very early on 
which led down this whole muckup was thinking that these did the 
'connect' and PeerConnector did the encryption).

This distinction is supported directly by the fact that this logic in 
these functions is identical for clients and servers.

** In no way does a TLS client code in PeerConnector accept(2) a 
connection. Therefore this logic is not doing accept(2).

b) Likewise, it is also not performing connect(2) equivalent semantics.

This is where your insistence that TLS connection and TCP connection are 
equivalent falls down completely. Because a TLS connection _exists_ as a 
result of these functions, but cannot be used for I/O.
  In order to use as a transport channel a session must also be 
negotiated. That session negotiation is the equivalent of connect(2) - 
yet it does *not* create a "TLS connection" - it creates a "TLS session".


In fact the more I think about it now, these functions are somewhat a 
TLS equivalent of socket(2). Since a socket/FD has to be allocated 
before a connection can begin to be actively started, and lots of 
behaviour flags etc get applied to the socket/FD after creation and 
before first use to manage the connections eventual behaviour.

For lack of anything actually suitable I bowed to your request to retain 
the Squid-3 terminology here. That being the words Create and 
Client/Server rather than connect/accept/listen/prepare etc.



> 
> All these functions should be inside the existing Security namespace. If
> you think we will have non-SSL/TLS things inside Security, then we can
> also add a Tls namespace, but I do not see the need for that right now.
> 

Er, they are in Security::

Lets talks a short side-step here and consider the Comm::Connection 
object design. It is supposed to be a generic abstraction for *any* 
transport (including TLS encrypted ones) such that the code using it 
does not need to be aware of whether it was TCP, UDP, SCTP, TLS, DTLS or 
whatever - just pass the Conn object to read/write API with a buffer and 
get that buffer filled or emptied.

With "TLS connection" being defined as being a pair [transport 
connection, TLS session]. The TLS connection "object" is most correctly 
typed as either std::pair<Comm::Connection, Security::SessionPointer>, 
OR adding a Comm::Connection with member pointing to the TLS session.

(ignoring for now that SessionPointer is currently borked).

Right now there is also a fuzzy line in the comm code between 
Comm::Connection and class fde, so IMO fde holding the SessionPointer is 
wrong, but that is where it currently has to be placed due to the CommIO 
handling logics. I'm intentionally leaving that tangled web out of scope 
for this patch.


I did consider making these functions methods of a class TlsConnection, 
but that would easily lead to confusion of thinking that class *was* 
representing a TLS connection and get in the way of future cleanup of 
the above tangle.

So for this patch I am simply adding a namespace placeholder for 
whatever the class will be and ensuring the static functions are in 
there. In the long term end product they may stay as statics like this 
in a class, or be renamed to non-static methods.

"Tls" is being used here to distinguish from Ssl:: things, but as you 
point out we have not gone far enough to warrant a Tls:: namespace yet. 
I do fully expect that there will be other security types before too 
much longer. Specifically some Security::SslFoo things. Then there is 
SCTP etc.

So making the name fully descriptive and avoiding even more renames 
seems to be a good choice. There should be no harm in documenting that 
these were created to be TLS specific things.


> 
>> +/// Create TLS state objects and associate with a TLS connection to form a TLS connection.
>> +/// Client connection structures and TLS/SSL I/O (Comm and BIO) are initialized.
> 
> 
>> +/// Create TLS state objects and associate with a TLS connection to form a TLS connection.
>> +/// Server connection structures and TLS/SSL I/O (Comm and BIO) are initialized.
> 
> 
> I am guessing something went wrong in the first sentences during
> find-and-replace ("TLS connection to form a TLS connection"). See below
> for a specific fix suggestion.

Oops. Yes. That first should be "TCP". Though using "transport" now as 
per below change.

> 
> Also, please avoid the "client connection" and "server connection"
> terminology, especially in high-level little-context descriptions like
> these, because such terms are very confusing in Squid context. As you
> know, we already have "client side" that has "server agents", and
> "server side" that has "client agents". To reduce confusion, use
> "from-client connection" and "to-server connection" phrasing instead
> (or, if you prefer, the verbose "client-to-Squid connection" and
> "Squid-to-server connection" variants.
> 

The Client/Server words are following our current Squid-oriented 
(Squid-as-Client and Squid-as-Server) terminology.

ie. "Client connection structures" refers to TLS connection structures 
where Squid is the client.

The TLS terminology, Squid terminology, library APIs seem to align. Only 
the BIO enum naming uses server/client the other way around, and those 
explicitly state "_TO_" for clarity. So I don't seen much in the way of 
confusion here.



> Please consider using these replacements:
> 
> /// Creates a TLS Connection and
> /// associates it with the given from-client transport connection.
> /// \returns false on errors (and logs details using DBG_IMPORTANT)
> 
> /// Creates a TLS Connection and
> /// associates it with the given to-server transport connection.
> /// \returns false on errors (and logs details using DBG_IMPORTANT)
> 

Done the \return change. The other doc changes are wrong because the 
CreateClient uses a to-server transport connection to generate a 
to-server / from-Squid TLS connection.


> 
> The other comments are about relatively minor problems:
> 
> 
>> + * Initializes TLS data structures and associates with a TCP Connection
>> + * to form a Client or Server TLS Connection.
> 
>> + * Initiates encryption on a TCP Connection to peers or servers.
> 
>> + * The caller must monitor the connection for TCP closure because this job will
> 
> 
> s/TCP Connection/transport connection/g
> 
> s/the connection for TCP/the transport connection for/
> 
> because when we start supporting SslBump for HTTPS proxies and/or HTTP/2
> for HTTPS proxies, that transport will not be TCP. There is nothing
> specific to TCP in that code IIRC.

Done.


> 
> Please apply similar adjustments to other "TCP" phrase added by the patch.
> 
> 
>> + * Initializes TLS data structures and associates with a TCP Connection
>> + * to form a Client or Server TLS Connection.
> 
> s/associates with/associates them with/

Done.


>> + * Initializes TLS data structures and associates with a TCP Connection
>> + * to form a Client or Server TLS Connection.
> 
> I would replace "to form a Client or Server TLS Connection" with "to a
> TLS Connection with a Client or Server".
> 

Nouns. The TLS data structures are not being associated with a TLS 
connection, they *are* the "Client TLS" or "Server TLS" part that makes 
the transport turn into a "Client or Server TLS connection" 
collective/aggregate thing.


> 
>> ... The primary operational
>> + * difference between the server and client is that the server is
>> + * generally authenticated, while the client is only optionally
>> + * authenticated."
> 
> I recommend removing that text -- that "primary operational difference"
> has little to do with the CreateTlsConnection code.
> 
> Overall, quoting fairly generic "client" and "server" definitions feels
> like noise to me, but I am not going to fight you about that.
> 

That is the distinguishing factor for client vs server at this level of 
TLS. It relates directly to what is correct handling of the BIO 
TO_SERVER/TO_CLIENT parameter sent to this function.


Sadly that is as detailed as they are. Quoting in full in part documents 
where the line is between the fuzzy formal definitions and anything we 
tack on to, as you said earlier, 'fill the gaps'.


> 
>> -    // Temporary ssl for getting X509 certificate from SSL_CTX.
>> -    Security::SessionPointer ssl(Security::NewSessionObject(ctx));
>> +    // Temporary Pointer<SSL> for getting X509 certificate from SSL_CTX.
>> +    Security::TlsConnection::Pointer ssl(Security::TlsConnection::NewSslObject(ctx));
> 
> s/Pointer<SSL>/SSL object/
> 
> ... because the comment is about the temporary OpenSSL SSL object, not
> the pointer to it (the local pointer variable is also temporary, but
> that is not the point here -- it is the temporary nature of the
> underlying SSL object that is rather unusual and worth commenting on).

Okay, done.


> 
> 
>> PS: Applying the definitions to PeerConnector, it has become clear that
>> it (and children) not following a MUST requirement about the underlying
>> TCP transport connection being terminated in the case where Handshake
>> negotiation failed due to a Record protocol violation. They are leaving
>> this closure to the caller which is a layering violation
> 
> There is no layering violation in letting the transport-aware caller to
> do transport-specific things. I seriously doubt separating handshake
> failure detection code from the code reacting to that failure violates
> any RFC MUSTs! There are certainly interface problems between
> PeerConnector and its users, but they are mostly software problems
> unrelated to RFCs/terminology and are outside this thread scope AFAICT.
> 

Maybe I was not clear enough.

* The layering violation is in requiring the caller / semantics layer to 
be aware of TLS syntax and how issues there need to be handled.

* The RFC violation is that the caller does *not* perform the close due 
to the protocol syntax errors. It seems to instead die on semantic 
interpretations of the bad syntax, which might be leaving nasty security 
holes on some garbage.

The TLS layer already is aware that there is a transport (relatively 
opaque in type though). So it is already in a position to close() that 
transport as required in the spec and let the caller do whatever its 
handler was for that.

The caller already has a close handler in place to do its own "stuff" 
when TLS layer aborts with the close().


Thank you
Amos


More information about the squid-dev mailing list