TLSPOOL_STARTTLS(3)

πŸ“¦ version 0.9.7, in nixos 26.05

πŸ’… TLSPOOL_STARTTLS πŸ’…

ok so this is TLSPOOL_STARTTLS(3), straight out of the Library Calls section, and bestie it is a lot β€” but it's literally the main character of the whole TLS Pool so buckle up πŸŽ€


✨ NAME ✨

tlspool_starttls β€” the glow-up where you take a plaintext connection and wrap it in TLS πŸ”₯


πŸŽ€ SYNOPSIS πŸŽ€

#include <tlspool/commands.h>
#include <tlspool/starttls.h>

int tlspool_starttls (int cryptfd, starttls_t *tlsdata,
       void *privdata,
       int (*namedconnect) (starttls_t *tlsdata, void *privdata));

πŸ¦‹ DESCRIPTION πŸ¦‹

okay so tlspool_starttls() is the main facilitation function of the TLS Pool β€” it starts a TLS session under control of the TLS Pool. and like, when I say "under control" I mean the TLS Pool encapsulates all the concerns of security and honestly most of the ones that relate to privacy too?? the application that calls tlspool_starttls() talks to the TLS Pool in terms of local and remote identities, but not in terms of credentials like certificates, keys or passwords β€” and also not in terms of policy settings or any other mechanistic aspects of TLS. none of that is your problem anymore, it's giving delegation πŸ’…

and no cap, it has been known that an application could implement TLS functionality in a matter of hours, with extreme examples of needing just half an hour of programming effort 😭 the cause of this is that no concerns related to TLS itself are left in the hands of the application, which can therefore focus entirely on what it does best β€” implement application logic. slay.

aside from programming simplicity, there's also the benefit of separate control over security matters and application content matters, which parallels operational practice, both in terms of system administration and software update responsibilities. it's giving ✨separation of concerns✨

the cryptfd handle supplies the TLS connection that is assumed to have been setup. when tlspool_starttls() ends, either in success or failure, this handle will no longer be available to the caller β€” the responsibility of closing it is passed on to the function and/or the TLS Pool. so like. don't touch it after. it's not yours anymore 🫢

the tlsdata structure will be copied into the command structure, and upon completion it will be copied back. you can use it to communicate flags, protocols and other parameters, including the most important settings β€” local and remote identifiers. see the socket protocol document for details.

the privdata handle is used in conjunction with the namedconnect() call; it is passed on to connect the latter to the context from which it was called and is not further acted upon by this function. the namedconnect() function is called when the identities have been exchanged, and established, in the TLS handshake. this is the point at which a connection to the plaintext side is needed, and a callback to namedconnect() is made to find a handle for it. the function is called with a version of the tlsdata that has been updated by the TLS Pool to hold the local and remote identities. the return value should be -1 on error, with errno set, or it should be a valid file handle that can be passed back to the TLS Pool to connect to.

when the namedconnect argument passed is NULL, default behaviour is triggered πŸ‘€ this interprets the privdata handle as an (int *) holding a file descriptor. if its value is valid, that is >= 0, it will be returned directly; otherwise, a socketpair(2) is constructed, one of the sockets is stored in privdata for use by the caller and the other is returned as the connected file descriptor for use by the TLS Pool. this means that the privdata must be properly initialised for this use, with either -1 (to create a socketpair) or the TLS Pool's plaintext file descriptor endpoint. the file handle returned in privdata, if it is >= 0, should be closed by the caller, both in case of success and failure. yeah. both. don't forget πŸ™ˆ


🌸 the fields in tlsdata when you CALL it 🌸

  • flags β€” see PIOF_STARTTLS_xxx below
  • local β€” may hold locally defined bits (none at the present time)
  • ipproto β€” one of the values IPPROTO_TCP, IPPROTO_UDP and IPPROTO_SCTP
  • streamid β€” when ipproto is set to IPPROTO_SCTP, this is the stream identifier on which to apply the STARTTLS request. it is common for SCTP to negotiate TLS in the full-blown manner over stream 0, and then to derive keys for the other streams from the master key of that one stream. iykyk πŸ’«
  • localid β€” is the local identity string. this string may be empty if no value is known. when functioning as a TLS client, the TLS Pool will take the disclose.db and tlspool_localid_service(3) mechanisms into account to filter this string's disclosure to the TLS server, or to do things such as substitution of a pseudonym, alias, group or role. iconic.
  • remoteid β€” is the remote identity string. this string may be empty if no value is known. when functioning as a TLS client, this value is used as a key for the disclose.db and/or the tlspool_localid_service(3) in determining whether to conceal the localid value to this remote.
  • ctlkey β€” is the control key for later use with tlspool_ctlkey_detach(3) and tlspool_ctlkey_reattach(3). the value provided to the tlspool_starttls() call should be filled with random data, both to prevent guessing the value in a rogue process, and to minimise the chances of an error due to hitting upon an already known control key. random. not "hunter2". please 🫠
  • service β€” is the IANA-standardised service name, as also stored in the services(5) database. this can be used by the TLS Pool in its efforts to isolate security mechanisms from applications, so it is valuable that it is set to a proper value.
  • timeout β€” is the number of milliseconds that the TLS handshake process waits for traffic from the remote peer. the special value 0 means that the default timeout will be used; the special value ~0 is interpreted to mean that no timeout should be applied by the TLS Pool.

🌈 the fields in tlsdata when it COMES BACK successfully 🌈

  • flags β€” see PIOF_STARTTLS_xxx below
  • local β€” may hold locally defined bits (none at the present time)
  • ipproto β€” would not have changed.
  • streamid β€” would not have changed.
  • localid β€” is the authenticated identity of the local TLS end point. this same identity is passed to the remote peer through a TLS mechanism, if the remote asked for it. the value may be empty if no local identity is available to the remote peer.
note that the precise choice of the TLS security mechanism is of no concern to the application that called tlspool_starttls() β€” any security concerns about mechanisms to use and not use are part of the policy interface to the TLS Pool, which is not linked to the application but to an administrative interface, namely a local database. not your circus, not your monkeys πŸ’…
  • remoteid β€” is the authenticated identity of the remote TLS end point. if no identity is known, or if it was not authenticated in a way that would not count as a TLS error, then this value may be set to the empty string.
  • ctlkey β€” would not have changed.
  • service β€” would not have changed.
  • timeout β€” would not have changed.

πŸ‘‘ the PIOF_STARTTLS_xxx flags πŸ‘‘

various PIOF_STARTTLS_xxx flags are sent and received in the tlsdata structure. when sent to the TLS Pool, they may provide it some freedom; when it is still set in the response then this freedom has been exercised. other flags indicate additional requirements β€” when these are not met, an error will be raised. their meaning in the response is meaningless. yeah, meaningless. don't read into it πŸ’€

the following flags are recognised by the TLS Pool:

  • PIOF_STARTTLS_LOCALROLE_CLIENT, PIOF_STARTTLS_LOCALROLE_SERVER, PIOF_STARTTLS_LOCALROLE_PEER, PIOF_STARTTLS_REMOTEROLE_CLIENT, PIOF_STARTTLS_REMOTEROLE_SERVER and PIOF_STARTTLS_REMOTEROLE_PEER β€” define whether the local or remote should act as a client or as a server. this is the TLS relationship, and may or may not match the transport connection over which TLS runs.

each side may be setup to act as a peer, which means it will mirror the other side. when either side is setup as a peer, the TLS Pool will begin as a client, but employ a TLS extension that can ignore the ClientHello from one of the sides β€” this is not currently a part of TLS, but may be added later on, in support of peer-to-peer connections as drafted in draft-vanrein-tls-p2p. future vibes only πŸ¦‹

at some point, the TLS transaction has an obvious client and server side, even in peer-to-peer connections, and a normal handshake commences. but the remote role helps to decide which forms of identity are acceptable, and when a remote peer effectively became a server it may still present a client credential, and the similar freedom may also be assumed by the local side, although the "right" kind of credential is preferred.

  • PIOF_STARTTLS_DTLS β€” requests to setup DTLS instead of TLS.
  • PIOF_STARTTLS_WITHOUT_SNI β€” can be used for client-side STARTTLS as an indication that if the remoteid is present then its domain should not be passed over to the other side as a Server Name Indication. this is not a common structure for all protocols, but is sent by default because it is an indicative TLS option. note that it is useful for xxxxs: protocols, which immediately start TLS, but usually not needed for protocols that issue a STARTTLS command during a normal exchange. anyhow, this is application-determined. if the remoteid contains a user@ part, it is not sent as part of the SNI information, because that would violate the format. that is a missed opportunity though πŸ˜”
  • PIOF_STARTTLS_IGNORE_CACHES β€” requires the TLS Pool to perform the validation here and now. it will not accept cached results from recent encounters as sufficient proof that the remote peer has the acclaimed identity. this can be used at places in an interaction where the identity of the remote peer must be firmly established. note that bypassing the caches dramatically increases the amount of work for the TLS Pool, and should thus be used with care 🫢 note that the validation outcome may still be cached, for future use when the peer relation is more relaxed. so it's expensive but it's not wasted, ok?
  • PIOF_STARTTLS_REQUEST_REMOTEID β€” means that the TLS Pool should not strictly require, but merely request a remote identity. this is useful if the remote peer is a client who may not have a certificate to authenticate with, and should still be able to access the service over TLS. it is also useful to permit anonymous TLS connections to remote clients or servers if both sides agree to that. consent-based anon, we love to see it ⭐
⚠️ bestie, quick warning before the next flag: a bidirectionally unauthenticated TLS connection is not protected from man in the middle attacks 😭. Its encryption may protect against passive observers, but that's the whole tea. Also: the flag we were just on is overridden by PIOF_STARTTLS_IGNORE_REMOTEID.
  • PIOF_STARTTLS_IGNORE_REMOTEID β€” tells the TLS Pool it doesn't even need to bother requesting a remote identity at all. If one is provided anyway, it is not validated. This is useful when the local application cannot use the remote identity in any useful way. It is also useful to permit anonymous TLS connections to remote clients or servers if both sides agree to that. Note that a bidirectionally unauthenticated TLS connection is not protected from man in the middle attacks, although it does warrant against passive observers. This flag overrides PIOF_STARTTLS_REQUEST_REMOTEID.
  • PIOF_STARTTLS_DETACH β€” instructs the TLS Pool to detach the TLS session from the client connection over which it was set up. That means no more control commands can be sent in relation to the TLS session until a client connection issues a successful tlspool_control_reattach(). In many applications, this flag will be combined with PIOF_STARTTLS_FORK, which has an independent meaning: PIOF_STARTTLS_FORK applies to the independent life of a TLS session that is run by the TLS Pool, and PIOF_STARTTLS_DETACH applies to the ability to send control commands in relation to a TLS session. The TLS Pool also implements one relationship between PIOF_STARTTLS_FORK and PIOF_STARTTLS_DETACH: after a PIOF_STARTTLS_FORK, the close-down of the client that set up a connection will automatically cause a PIOF_STARTTLS_DETACH of those TLS sessions. When the tlspool_starttls() exchange starts, the value in ctlkey is stored for future reference; control can be regained from any TLS Pool client connection that presents the ctlkey in tlspool_control_reattach(3). See also the tlspool_control_detach(3) function, which performs the action as a separate step.
  • PIOF_STARTTLS_FORK β€” instructs the TLS Pool that the TLS session should continue to run when the client connection over which it was set up closes. By default, TLS sessions are terminated when their requesting client disappears, for instance due to termination of the requesting program. PIOF_STARTTLS_FORK and PIOF_STARTTLS_DETACH are different concepts: PIOF_STARTTLS_FORK applies to the independent life of a TLS session that is run by the TLS Pool, and PIOF_STARTTLS_DETACH applies to the ability to send control commands in relation to a TLS session. Many applications will use the two combined. The TLS Pool also implements one relation: after a PIOF_STARTTLS_FORK, the close-down of the client that set up a connection will automatically cause a PIOF_STARTTLS_DETACH of those TLS sessions.
  • PIOF_STARTTLS_DOMAIN_REPRESENTS_USER β€” indicates that the remote identity need not be the expected user@domain, but that the domain is acceptable as well. This is a common flag on protocols such as SMTP, where a server represents all users under its domain, and authenticates as the domain instead of as the user. Note that the flag applies equally well to clients as it does to servers. If an application does not supply this flag, it must supply any remote_id field for a STARTTLS exchange in the exact format as it is supported by the server. The returned remote_id will always be the exact identity as provided by the server.
  • PIOF_STARTTLS_RENEGOTIATE β€” takes a previously agreed TLS connection and renegotiates identities as specified in this request's tlsdata. The ctlkey field indicates an attached TLS connection that is to be renegotiated; this field will not be modified in the course of this invocation of the tlspool_starttls() function.

πŸ’« RETURN VALUE πŸ’«

The function returns a file descriptor >= 0 on success πŸŽ‰. If an error occurs, the function returns -1 and errno is set appropriately.

✍️ AUTHOR ✍️

Written by Rick van Rein of OpenFortress.nl, for the ARPA2.net project.

πŸ› REPORTING BUGS πŸ›

For any discussion, including about bugs, please use the mailing list found on http://lists.arpa2.org/mailman/listinfo/tls-pool.

Please read the software distribution's README, INSTALL and TODO files for information about the tlspool-daemon implementation status.

Copyright Β© 2015 Rick van Rein, ARPA2.net.

ARPA2 is funded from InternetWide.org, which in turn receives donations from various funding sources with an interest in a private and secure Internet that gives users control over their online presence. This particular project has been sponsored in part by NCSC.

🌈 SEE ALSO 🌈

The configuration file options allow_facilities and deny_facilities can specify the starttls facility to allow, respectively disable this facility. Whether this has been done can be checked with tlspool_ping(3).

The TLS Pool API is documented in the include file <tlspool/commands.h> and <tlspool/starttls.h> for C, and the tlspool.py module for Python.

Online resources may be found on the project home page, http://tlspool.arpa2.net.

muah πŸ’‹ β€” sourced from ARPA2.net, dated November 2015, page TLSPOOL_STARTTLS(3), signing off ✨🫢

πŸ“¦ where this page comes from