Can a linux service work as both TLS client and server?

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

Can a linux service work as both TLS client and server?

Kristen J. Webb
Is there a way for a single program to act as both a TLS client and a TLS server after a TCP/IP accept() call?

Today, I simply have the TCP connecting process issue a 1 or 0 to indicate how it is acting.  This is then used to determine who does SSL_accept and SSL_connect and everything works out.  My original idea was that I could then configure any number of supporting services on the same port going forward.

I'd like to remove this 1 time TCP write/read operation. For example, I cannot see how this will work with Apple's network framework going forward.

I currently have 3 authentication use cases

      Server side cert (currently only works in one direction without my workaround)
      Server side cert with GSSAPI (currently only works in one direction without my workaround)
      Client/Server certs (so this one should work either way)

Will PSK allow my service to say, always act as a TLS server without a server certificate?
Could I then proceed with additional certificate functions (e.g. for GSSAPI)?

Or should I go back and grovel for another port and use this information to
explain why I need one?

Many thanks in advance for any insights!

Kris
--
This message is NOT encrypted
--------------------------------
Mr. Kristen J. Webb
Chief Technology Officer
Teradactyl LLC.
2450 Baylor Dr. S.E.
Albuquerque, New Mexico 87106
Phone: 1-505-338-6000
Email: [hidden email]
Web: http://www.teradactyl.com



Providers of Scalable Backup Solutions
   for Unique Data Environments

--------------------------------
NOTICE TO RECIPIENTS: Any information contained in or attached to this
message is intended solely for the use of the intended recipient(s). If
you are not the intended recipient of this transmittal, you are hereby
notified that you received this transmittal in error, and we request
that you please delete and destroy all copies and attachments in your
possession, notify the sender that you have received this communication
in error, and note that any review or dissemination of, or the taking of
any action in reliance on, this communication is expressly prohibited.


Regular internet e-mail transmission cannot be guaranteed to be secure
or error-free. Therefore, we do not represent that this information is
complete or accurate, and it should not be relied upon as such. If you
prefer to communicate with Teradactyl LLC. using secure (i.e., encrypted
and/or digitally signed) e-mail transmission, please notify the sender.
Otherwise, you will be deemed to have consented to communicate with
Teradactyl via regular internet e-mail transmission. Please note that
Teradactyl reserves the right to intercept, monitor, and retain all
e-mail messages (including secure e-mail messages) sent to or from its
systems as permitted by applicable law
Reply | Threaded
Open this post in threaded view
|

Re: Can a linux service work as both TLS client and server?

Phil Neumiller
Sure, you just need additional threads.  Note: accept is a blocking call so
the thread that runs in (i.e. your server side will block until a packet is
received).  You can write a polling loop using select, that doesn't block.
The cleanest thing to do is have a thread for client(s) and one for server.
I have done this with C++17 with TLS1_3_Client and TLS1_3_Server classes
with accept loop member functions started as std::thread.



-----
Phillip Neumiller
Platform Engineering
Directstream, LLC
--
Sent from: http://openssl.6102.n7.nabble.com/OpenSSL-User-f3.html
Phillip Neumiller Platform Engineering Directstream, LLC
Reply | Threaded
Open this post in threaded view
|

Re: Can a linux service work as both TLS client and server?

Kristen J. Webb
Hi Phil,
Thanks for such a fast response!  I am doing the polling today.

I believe I left something very important out of my original question.
I only have 1 well known port to accept all of my connections.

TLS_client_app -> service on portA (needs to be a TLS_server)
TLS_server_app -> service on portA (needs to be a TLS_client)

The problem is that when the service accept()'s the connection it does
not know what type of app made the connection so it cannot decide
if it should act as the TLS client or server (unless I send a 1/0 hint
over TCP first).

Kris




On Fri, Nov 15, 2019 at 3:28 PM Phil Neumiller <[hidden email]> wrote:
Sure, you just need additional threads.  Note: accept is a blocking call so
the thread that runs in (i.e. your server side will block until a packet is
received).  You can write a polling loop using select, that doesn't block.
The cleanest thing to do is have a thread for client(s) and one for server.
I have done this with C++17 with TLS1_3_Client and TLS1_3_Server classes
with accept loop member functions started as std::thread.



-----
Phillip Neumiller
Platform Engineering
Directstream, LLC
--
Sent from: http://openssl.6102.n7.nabble.com/OpenSSL-User-f3.html


--
This message is NOT encrypted
--------------------------------
Mr. Kristen J. Webb
Chief Technology Officer
Teradactyl LLC.
2450 Baylor Dr. S.E.
Albuquerque, New Mexico 87106
Phone: 1-505-338-6000
Email: [hidden email]
Web: http://www.teradactyl.com



Providers of Scalable Backup Solutions
   for Unique Data Environments

--------------------------------
NOTICE TO RECIPIENTS: Any information contained in or attached to this
message is intended solely for the use of the intended recipient(s). If
you are not the intended recipient of this transmittal, you are hereby
notified that you received this transmittal in error, and we request
that you please delete and destroy all copies and attachments in your
possession, notify the sender that you have received this communication
in error, and note that any review or dissemination of, or the taking of
any action in reliance on, this communication is expressly prohibited.


Regular internet e-mail transmission cannot be guaranteed to be secure
or error-free. Therefore, we do not represent that this information is
complete or accurate, and it should not be relied upon as such. If you
prefer to communicate with Teradactyl LLC. using secure (i.e., encrypted
and/or digitally signed) e-mail transmission, please notify the sender.
Otherwise, you will be deemed to have consented to communicate with
Teradactyl via regular internet e-mail transmission. Please note that
Teradactyl reserves the right to intercept, monitor, and retain all
e-mail messages (including secure e-mail messages) sent to or from its
systems as permitted by applicable law
Reply | Threaded
Open this post in threaded view
|

Re: Can a linux service work as both TLS client and server?

Phil Neumiller
Yes, so you accept thread needs to either fork() or spawn another thread to
process the packet and go back into the accept loop for another connection.



-----
Phillip Neumiller
Platform Engineering
Directstream, LLC
--
Sent from: http://openssl.6102.n7.nabble.com/OpenSSL-User-f3.html
Phillip Neumiller Platform Engineering Directstream, LLC
Reply | Threaded
Open this post in threaded view
|

Re: Can a linux service work as both TLS client and server?

Kristen J. Webb
In the future, I will not have an initial TCP 1/0 packet (clue) to process.
So I have no way to decide if my forked/spawned process should SSL_connect
or SSL_accept.

For example, I cannot see how this can be done with Apple's network framework
(at least not yet).  It appears to be so high level as to not allow me
to process a TCP packet within a TLS style connection.  I realize that this is not
an openssl issue.  And I do have things working today with Apples security
framework and openssl (with that extra TCP packet clue in place).  I am more familiar
with openssl and I'm trying to code everything there first.  Also my entire application
runs on linux so I am able to test all the combinations easily from there.  And I'll
need it to work with Apple's networking in the future as their security APIs go away.

Thank you for bearing with me so far!





On Fri, Nov 15, 2019 at 4:01 PM Phil Neumiller <[hidden email]> wrote:
Yes, so you accept thread needs to either fork() or spawn another thread to
process the packet and go back into the accept loop for another connection.



-----
Phillip Neumiller
Platform Engineering
Directstream, LLC
--
Sent from: http://openssl.6102.n7.nabble.com/OpenSSL-User-f3.html


--
This message is NOT encrypted
--------------------------------
Mr. Kristen J. Webb
Chief Technology Officer
Teradactyl LLC.
2450 Baylor Dr. S.E.
Albuquerque, New Mexico 87106
Phone: 1-505-338-6000
Email: [hidden email]
Web: http://www.teradactyl.com



Providers of Scalable Backup Solutions
   for Unique Data Environments

--------------------------------
NOTICE TO RECIPIENTS: Any information contained in or attached to this
message is intended solely for the use of the intended recipient(s). If
you are not the intended recipient of this transmittal, you are hereby
notified that you received this transmittal in error, and we request
that you please delete and destroy all copies and attachments in your
possession, notify the sender that you have received this communication
in error, and note that any review or dissemination of, or the taking of
any action in reliance on, this communication is expressly prohibited.


Regular internet e-mail transmission cannot be guaranteed to be secure
or error-free. Therefore, we do not represent that this information is
complete or accurate, and it should not be relied upon as such. If you
prefer to communicate with Teradactyl LLC. using secure (i.e., encrypted
and/or digitally signed) e-mail transmission, please notify the sender.
Otherwise, you will be deemed to have consented to communicate with
Teradactyl via regular internet e-mail transmission. Please note that
Teradactyl reserves the right to intercept, monitor, and retain all
e-mail messages (including secure e-mail messages) sent to or from its
systems as permitted by applicable law
Reply | Threaded
Open this post in threaded view
|

Re: Can a linux service work as both TLS client and server?

Sam Roberts
I'm curious, its pretty unusual to not know which side of a TCP connection is the client or server, not just TLS, HTTP, SMTP, .... etc. Its almost always the side that makes the accept() call that's the server, but that doesn't have to be.

Why is it that you do not in this context?

Without it, you are fairly far off the beaten path. A normal TLS client would not be able to connect to your "accept()" side if it tried to be a client, and a normal TLS server would never initiate a connection to your "accept()" in the hopes that the acceptor would turn around and be a client.

The 1/0 isn't so terrible (well, maybe the protocol is terrible :-). To do a custom negotiation, then "step up" to TLS is done by other protocols. You could also sniff the TCP after accept, and wait a while to see if a client hello arrives to know if the other side is a client (or wait for any data, I don't think a server starts sending data until it gets something, but its been a while since I looked).

Hope thats helpful, and even if not, it'd be interesting to know what apple is doing that is pushing you down this path.

Sam

Reply | Threaded
Open this post in threaded view
|

RE: Can a linux service work as both TLS client and server?

Michael Wojcik
In reply to this post by Kristen J. Webb
> From: openssl-users [mailto:[hidden email]] On Behalf Of Kristen Webb
> Sent: Friday, November 15, 2019 18:27
>
> So I have no way to decide if my forked/spawned process should SSL_connect
> or SSL_accept.
>
> For example, I cannot see how this can be done with Apple's network framework
> (at least not yet).  It appears to be so high level as to not allow me
> to process a TCP packet within a TLS style connection.

It's not entirely clear to me what you're trying to do. Is this a fair description?

1. You have a process (which happens to be running on Linux and is a "service", though that's not a specific thing on Linux) which is accepting TCP connections. In technical terms, it's doing TCP passive opens: it has a stream socket bound to a port, in LISTENING state, and it calls accept on that socket. (Whether you multiplex that, or use non-blocking accept, or just block in accept until it's ready is irrelevant.)

2. When you get a conversation (i.e. ESTABLISHED state) socket from accept, you want to perform one of two actions:

2.1. If the peer intends to act as a TLS client, you want to call SSL_accept to create the TLS tunnel. That is, you'll do a passive TLS open, which is what normal TLS applications would do following a passive TCP open.

2.2. If the peer intends to act as a TLS server, you want to call SSL_connect, performing the active TLS open even though you did a passive TCP open. This is weird, frankly; but there's nothing it TCP or TLS to prevent it.

2.3. However, you don't know what the peer intends to do yet.


There's no deterministic way of solving this. You only have one piece of information at this point: the conversation's 5-tuple address (address family, local IP address, local port, remote IP address, remote port). Conventionally, a TCP server (i.e. a process that does passive opens) which handles different client behaviors will establish the client's intent from either the local port or the initial transmission from the client. The former is out of the question, since the whole point of this exercise is to multiplex different behaviors on the same local port.

So, your program needs information from the client to figure out what to do. Offhand I see only one way to resolve this: you need to interpose logic between OpenSSL and the actual communications endpoint. OpenSSL has a standard mechanism for this: the BIO pair.

You'll want to do something along these lines.

1. Determine how long you'll wait for an initial transmission from the client. You have to have some timeout here, because if the client's doing a passive TLS open it will wait for data from you. But then the FPL theorem says in general a distributed system has to employ timeouts anyway if it wants to guarantee completion. We're just making that requirement a bit more concrete. Let's say you'll wait for a configurable number of seconds, and default to, oh, 5s.

3. Rather than creating a socket BIO around your conversation socket as a normal OpenSSL application would, you create a BIO pair. One half of the pair will be the external BIO; you'll transfer data between that BIO and the socket. The other half of the pair will be the internal BIO, and that will be the one associated with OpenSSL operations. Create your SSL object and associate it with the internal BIO.

4. Wait for your conversation socket to become readable, for your timeout period.

4.1. If the socket becomes readable, do a conventional recv (or read, or the system call of your choice) on it. Handle errors and conversation termination as necessary. Mark the conversation as passive (you're the server, doing the TLS accept) in your own conversation information. Write the data to the external BIO.

4.2. If the socket does not become readable, mark the conversation as active and perform the SSL_connect on the internal BIO.

5. From this point on you want OpenSSL to operate on the internal BIO, while copying data between the socket and the extternal BIO. So start a thread that does the following:

5.1. Check to see if the socket is readable. If so, receive data (do error and termination handling) and write it to the external BIO. (If the external BIO's buffer is full, you may have to buffer the data somewhere else, or just yield your timeslice and hope the conversation-processing thread gets its act together.)

5.2. Check to see if the external BIO is readable. (See the OpenSSL man page for BIO_make_bio_pair for more information.) If so, read data from it and write to the socket. You can check the socket for writability first if you want to avoid blocking. (For a maximally-robust solution this all could get somewhat complicated; using a decent set of abstractions would be a goodd plan.)

5.3. If neither is readable, go to sleep. You can use poll() or similar here to sleep with a timeout on the socket becoming readable. Unfortunately you can't trivially multiplex on a BIO, as its internal descriptor (if it even has one) isn't exposed by the public API. You *could* set a callback on the external BIO that writes a trigger byte to a control pipe that you add to the poll set, if you want to get fancy. (As I said, this can get complicated.)

6. Meanwhile, your conversation thread goes off and does its conversation stuff, using the SSL object you created before.


Actually, having written all that, it occurs to me there's an easier approach. When you get the conversation socket, wait for the timeout period for it to become readable. If it does, mark the conversation as passive; if it doesn't, mark it as active. Start your conversation logic. The first thing that should do is look at that active/passive flag and do an SSL_connect or an SSL_accept. You don't need the BIO pair because you don't care about what the data before OpenSSL reads it or before its sent to the peer; you just care whether there *is* data from the peer, within the timeout window at the beginning of the conversation.

The BIO-pair arrangement is useful if you need to intervene more extensively at the layer between OpenSSL and the network endpoint for some reason, e.g. to do sophisticated buffering or to communicate using some non-BIO-compatible interface.

--
Michael Wojcik
Distinguished Engineer, Micro Focus


Reply | Threaded
Open this post in threaded view
|

Re: Can a linux service work as both TLS client and server?

Karl Denninger
In reply to this post by Kristen J. Webb
On 11/15/2019 17:27, Kristen Webb wrote:
In the future, I will not have an initial TCP 1/0 packet (clue) to process.
So I have no way to decide if my forked/spawned process should SSL_connect
or SSL_accept.

For example, I cannot see how this can be done with Apple's network framework
(at least not yet).  It appears to be so high level as to not allow me
to process a TCP packet within a TLS style connection.  I realize that this is not
an openssl issue.  And I do have things working today with Apples security
framework and openssl (with that extra TCP packet clue in place).  I am more familiar
with openssl and I'm trying to code everything there first.  Also my entire application
runs on linux so I am able to test all the combinations easily from there.  And I'll
need it to work with Apple's networking in the future as their security APIs go away.

Thank you for bearing with me so far!

I don't quite understand what you're attempting to do, or why.

I assume (since you're sending the initial packet) that the "thing" connecting to the OpenSSL end is under your control (it's your code.)  If so, why do you care which "way" the listening end comes up?

By convention if you are doing a listen() on an a socket then you're a server.  You don't have to be from an SSL perspective, but from a socket perspective you absolutely are.

So why do you want to select "which way" you do this on the TLS/SSL end?  Is it a function of which end has a certificate (or whether both do) and which one(s) you care to verify (or not)?  If so that can be dealt with through options and who checks what, rather than what you're doing now.

I'm trying to understand the workflow you are attempting to implement, and why, because I suspect you may be going about this the hard way.

--
Karl Denninger
[hidden email]
The Market Ticker
[S/MIME encrypted email preferred]

smime.p7s (6K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Can a linux service work as both TLS client and server?

Viktor Dukhovni
In reply to this post by Kristen J. Webb
On Fri, Nov 15, 2019 at 03:10:55PM -0700, Kristen Webb wrote:

> Is there a way for a single program to act as both a TLS client and a TLS
> server after a TCP/IP accept() call?

Yes, but as you're aware and others have mentioned it has to decide
which somehow.

> Today, I simply have the TCP connecting process issue a 1 or 0 to indicate
> how it is acting.  This is then used to determine who does SSL_accept and
> SSL_connect and everything works out.

That's one valid way to do that.  Whoever is the server will need
some sort of server certificte or have a PSK in common with the
client.  The client can also use ia certificate, or authenticate
via GSSAPI after the TLS connection is established, it could also
perform GSSAPI channel binding to the server certificate.

> Will PSK allow my service to say, always act as a TLS server without a
> server certificate?

Yes.  And you can even negotiate the PSK via an initial GSSAPI
session establishment.  Then just use a nominal PSK id (say a single
'\0' byte) that signals the just negotiated PSK.  Here you might
have the TCP client also always be the GSSAPI initiator, but tell
the (TCP/GSSAPI) server who will be the TLS server.

> Could I then proceed with additional certificate functions (e.g. for
> GSSAPI)?

With that you would not need after-the-fact GSSAPI, because GSSAPI
authentication is implied via the PSK.

--
    Viktor.
Reply | Threaded
Open this post in threaded view
|

Re: Can a linux service work as both TLS client and server?

Kristen J. Webb
First, thanks to everyone for all the useful feedback.  I really appreciate it!

Let me try to explain my situation again as to why I need a service to do both.

1. I have a single service listening on a well known port.  it is a backup service that runs on the backup server which will always be
the TLS_server (will always have a certificate).  The same service runs on multiple backup clients where it acts as the TLS_client,
listening for connections from the backup server.
2. In a common mode, a separate backup server process (TLS_server) will connect to it and the backup service needs to act as a TLS_client.
3. In another mode a backup client (TLS_client) will connect the backup service on the backup server and that service needs to act as a TLS_server

It sounds like peeking at the port may be the simplest way to determine how it is being connected to.
As I write this I realize that the service running on all of the other backup clients really only needs 2.
In this case, the backup client is a TLS_client, but it will be doing the TCP accept.  No need to decide
which mode to use in this case..  It is the backup server's backup service that needs to do both
and will always be a linux server, so setting up peek should work well.

Apple has a network framework (supports TLS 1.3) that I believe will eventually replace the current security framework (supports
up to TLS 1.2) that I am using today to get the job done.  There is example code here:


I have been experimenting with this code.  I could not get it to work on Mojave, but I could get it
to work on Catalina.  To summarize how I think it works:

1. You set up all of the connection parameters up front (TCP, TLS, TLS-PSK, UDP, bonjour, etc, etc).
2. Next, create an endpoint using nw_endpoint_create_host
3. In the case of a service (listener) call nw_listener_create with the parameters.

You now have an opaque object and in TLS mode, I do not see a way to access the underlying TCP socket.
I've just realized that I need to do more testing against my common, but odd case, where my client's
backup service needs to accept, but process w/o a cert as a TLS_client.  Joy!

Doing more digging today, I find in  https://forums.developer.apple.com/thread/116221

__BEGIN_COMMENTS__
I've not seen an equivalent way of message peeking
Such a mechanism does not exist.

or even getting the … socket.
Nor does that, at least in general.  Network framework was designed to work in conjunction with our user space networking stack, and that stack does not have an underlying socket because sockets are a kernel-only concept.

Now, on macOS, Network framework does actually talk to the kernel, but that’s just a compatibility measure: We can’t enable the user space networking stack on the Mac while continuing to support Network Kernel Extensions (NKEs).  NKEs have been informally deprecated for a while now, so the expectation is that they’ll be formally deprecated and then removed in future OS releases, at which point macOS will work like all our other OSes in this regard.

You can learn more about the background to this in:

WWDC 2017 Session 707 Advances in Networking, Part 1

WWDC 2018 Session 715 Introducing Network Framework

All of this is to say that, if you can’t do what you want with Network framework, the time to an enhancement request for the facilities that you need is now.
__END_COMMENTS

It appears that if you do not keep up with the apple way of doing things on OSX at some point you will be locked out?

Kris


On Fri, Nov 15, 2019 at 8:10 PM Viktor Dukhovni <[hidden email]> wrote:
On Fri, Nov 15, 2019 at 03:10:55PM -0700, Kristen Webb wrote:

> Is there a way for a single program to act as both a TLS client and a TLS
> server after a TCP/IP accept() call?

Yes, but as you're aware and others have mentioned it has to decide
which somehow.

> Today, I simply have the TCP connecting process issue a 1 or 0 to indicate
> how it is acting.  This is then used to determine who does SSL_accept and
> SSL_connect and everything works out.

That's one valid way to do that.  Whoever is the server will need
some sort of server certificte or have a PSK in common with the
client.  The client can also use ia certificate, or authenticate
via GSSAPI after the TLS connection is established, it could also
perform GSSAPI channel binding to the server certificate.

> Will PSK allow my service to say, always act as a TLS server without a
> server certificate?

Yes.  And you can even negotiate the PSK via an initial GSSAPI
session establishment.  Then just use a nominal PSK id (say a single
'\0' byte) that signals the just negotiated PSK.  Here you might
have the TCP client also always be the GSSAPI initiator, but tell
the (TCP/GSSAPI) server who will be the TLS server.

> Could I then proceed with additional certificate functions (e.g. for
> GSSAPI)?

With that you would not need after-the-fact GSSAPI, because GSSAPI
authentication is implied via the PSK.

--
    Viktor.


--
This message is NOT encrypted
--------------------------------
Mr. Kristen J. Webb
Chief Technology Officer
Teradactyl LLC.
2450 Baylor Dr. S.E.
Albuquerque, New Mexico 87106
Phone: 1-505-338-6000
Email: [hidden email]
Web: http://www.teradactyl.com



Providers of Scalable Backup Solutions
   for Unique Data Environments

--------------------------------
NOTICE TO RECIPIENTS: Any information contained in or attached to this
message is intended solely for the use of the intended recipient(s). If
you are not the intended recipient of this transmittal, you are hereby
notified that you received this transmittal in error, and we request
that you please delete and destroy all copies and attachments in your
possession, notify the sender that you have received this communication
in error, and note that any review or dissemination of, or the taking of
any action in reliance on, this communication is expressly prohibited.


Regular internet e-mail transmission cannot be guaranteed to be secure
or error-free. Therefore, we do not represent that this information is
complete or accurate, and it should not be relied upon as such. If you
prefer to communicate with Teradactyl LLC. using secure (i.e., encrypted
and/or digitally signed) e-mail transmission, please notify the sender.
Otherwise, you will be deemed to have consented to communicate with
Teradactyl via regular internet e-mail transmission. Please note that
Teradactyl reserves the right to intercept, monitor, and retain all
e-mail messages (including secure e-mail messages) sent to or from its
systems as permitted by applicable law
Reply | Threaded
Open this post in threaded view
|

RE: Can a linux service work as both TLS client and server?

Michael Wojcik
> From: openssl-users [mailto:[hidden email]] On Behalf Of Kristen Webb
> Sent: Saturday, November 16, 2019 10:22

> It sounds like peeking at the port may be the simplest way to determine how it is
> being connected to.

Using different ports for different types of services - which is what you have here - is the traditional approach, yes. I'm not sure why you refer to this as "peeking", since it's really a matter of having two endpoints; when you accept a conversation, you already know what endpoint it has arrived on.

> Apple has a network framework (supports TLS 1.3) that I believe will eventually replace the
> current security framework (supports up to TLS 1.2) that I am using today to get the job
> done.

It sounds like your problem is with Apple's API, not with OpenSSL, so I don't know that we can offer any further assistance.

--
Michael Wojcik
Distinguished Engineer, Micro Focus