For Development HEAD DRAFTSearch (procedure/syntax/module):

12.54 rfc.tls - Transport layer security

Module: rfc.tls

This module handles secure connection over TCP socket. This module is used by rfc.http to realize https connection (see rfc.http - HTTP client).

TLS subsystems

Whether the running Gauche has TLS support depends on the build options, and can be checked with a feature identifier gauche.net.tls. See Feature conditional, for more about feature identifiers.

Gauche uses MbedTLS (https://tls.mbed.org/) as TLS implementation. We used to support alternative subsystems, so the library is designed to handle multiple subsystems. In future we may support additional subsystems.

Class: <tls>

{rfc.tls} An abstract base class of a TLS implementation. You can use its instance to communicate with peer over secure connection. You usually don’t need to care the concrete subclass; just treat their instances as <tls> instance.

This inherits <connection> (see gauche.connection - Connection framework).

Class: <mbed-tls>

{rfc.tls} A class that implements MbedTLS subsystem interface.

Parameter: default-tls-class

{rfc.tls} The default TLS subsystem to be used. In the current version, it may just be <mbed-tls>, or #f if the system is not compiled with TLS support.

TLS common operations

Function: make-tls initargs …

{rfc.tls} Creates and returns a new TLS instance of the class default-tls-class. The returned TLS instance can be used either as a client, by passing it to tls-connect, or as a server, by passing it to tls-bind and tls-accept. See the following subsections for each usage.

The arguments must be a keyword-value list, and passed to the constructor of the TLS class. The following keyword arguments are recognized.

:server-name

Server name to be used for TLS Server Name Indication extension. In general, if you use the created TLS object as a client, you want to specify the server name. If you use the create TLS object as a server, you can omit this option.

:skip-verification

Client only. If the argument is true, skip server certificate verification upon connection. This is unsafe and should not be used except experimental purposes.

Function: tls-close tls

{rfc.tls} Shuts down the underling connection. The peer will notified the connection is closed. Once tls is closed, it can no longer be used.

You can also call connection-close on tls to get the same effect (see gauche.connection - Connection framework).

Function: tls-input-port tls
Function: tls-output-port tls

{rfc.tls} If tls is connected, they return input and output port to communicate with the peer, respectively.

If tls is not connected, #f is returned.

You can also call connection-input-port and connection-output-port on tls got get the same efffect (see gauche.connection - Connection framework).

Function: tls-poll tls rw :optional timeout

{rfc.tls} Wait for tls to be ready for reading or writing. The tls object must be already bound or connected; otherwise, it immediately returns ().

The rw argument is a list of symbols read and/or write, to specify what condition(s) to be checked. The timeout argument is either a <time> object to specify an absolute time point, a real number to specify the number of seconds from the current time, or #f to wait indefinitely. If omitted, #f is assumed.

The return value is a list of symbols that are satisfied. That is, if you pass (read) or (read write) in rw and the tls communication is ready to read, (read) is returned. If timeout reaches before any condition is met, () is returned.

Function: tls-debug-level-set! level

{rfc.tls} This is for troubleshooting. Set the global debug log level of the TLS subsystem to level, which is an exact integer between 0 (no debug logging, default) to 9 (maximum debug logging).

The actual granularity of log levels depends on the TLS subsystem, and 0-9 scale is mapped to each subsystem’s logging mechanism. You want some experiment to find appropriate value.

TLS client

When your code is a client to connect to a server over TLS, you need CA certificates to verify server certificates properly. Gauche doesn’t have its own CA certificates, and relies on the system’s certificate store by default. On Unix-based systems, we search several known locations: On popular Linux distributions we recommend you to install ca-certificates package (or similar one). On OSX, we recommend to install openssl via Homebrew. On Windows, we use system’s certificate store via Wincrypt API.

With the default configuration, Gauche checks the availability of the system’s certificate store at initilization and use one if available. You can explicitly give the path of CA certificate bundle, or disable it and provide individual certificate per connection.

If, for some reasons, you cannot install system-wide CA certificate bundle, you can also download Curl’s CA certificate bundle https://curl.haxx.se/ca/cacert.pem, and install it in Gauche installation directory. We have a convenience script. After installing Gauche, run the following command:

gosh tools/get-cacert

You need curl installed on your system. If you’ve installed Gauche with root priviledge, you’ll be asked sudo password to install the CA bundle file.

If you decided to do this, make sure you run the above command occasionally to get updated CA certificate bundles, for certificates may expire or be revoked.

Parameter: tls-ca-bundle-path :optional path

{rfc.tls} Holds CA certificate bundle to be used. The value can be either a string path to a CA bundle file, a symbol system, or #f.

If it is system, Gauche uses system’s default bundle. An error is signaled on connection if Gauche can’t find one.

If it is #f, CA certificate won’t be loaded automatically, and you have to manually load one using tls-load-object. (Note: This option is only valid with <ax-tls>. If you’re using <mbed-tls>, you need valid CA certificate bundle.)

With the default configuration, Gauche scans the system CA bundle when rfc.tls module is initialized, and if it finds one, tls-ca-bundle-path is set to system; otherwise, tls-ca-bundle-path is set to #f. So if you’re using with default configuration and you see its value is system, you can count on the system CA certificate bundle.

This default behavior may be altered if Gauche is configured with --with-ca-bundle option. You can execute gauche-config --reconfigure command to see if special --with-ca-bundle option is given.

Function: tls-connect tls host port :optional proto

{rfc.tls} Establishes TLS connection as a client.

The tls argument must be an unconnected TLS object. The host and port arguments are strings to specify server’s hostname and port. Besides the common hostname, IP notation (e.g. "127.0.0.1" or "[::1]") are allowed in host. Integre port number or a service name (e.g. "https") are allowed in port. The proto argument must be either one of the symbols tcp or udp. If omitted, tcp is assumed. (If it is udp, DTLS is used instead of TLS. However, we still lack some additional API support to make DTLS usable.)

Once the procedure contacted to the server, it obtains its server certificate and tries to validate it against the known CA certificates. If the server can’t be validated, an error is signaled. To establish a proper connection, a CA certificate storage must be specified by the parameter tls-ca-bundle-path.

Once the connection is established and TLS handshake is succeeded, the passed tls becomes ’connected’ state and can be used to read/write data from/to the connected peer.

TLS server

To open a TLS connection as a server, you have to prepare a private key, a server certificate, and intermediate certificates. Those must be loaded before accepting TLS connections from clients.

Function: tls-load-certificate tls path

{rfc.tls} Read and register server certifcate(s) stored in a file named by path. The given file may contain multiple certificates. You can call this multiple times to add intermediate certifictes.

Function: tls-load-private-key tls path password

{rfc.tls} Read and register server private key storead in a file named by path, with the password. If the private key file is not encrypted, you can pass #f to password.

Function: tls-bind tls host port :optional proto

{rfc.tls} Creates a server endpoint of tls connection.

The tls argument must be an unconnected, unbound TLS object. The host argument may be a string hostname or #f. The port argument is an integer or a string to specify the port. The proto argument must be either one of the symbols tcp or udp, and assumed tcp if omitted. (NB: udp server (DTLS) needs some more API support, so it is not very usable now.)

Like socket-bind, you can give 0 to port to let the system choose an available port number. The actual port number can be obtained by (sockaddr-port (connection-self-address tls)).

Function: tls-accept tls

{rfc.tls} The passed tls object must already be bound by tls-bind. Server certificates and private key must be already loaded to tls by tls-load-certificate and tls-load-private-key.

This waits for a client to connect to the bound endpoint. Once a client tries to connect, it present the server certificate and performs TLS handshake. If everything succeeds, returns a fresh tls object that can be used to read/write dat from/to the connected peer.

Connection methods

Since <tls> class implements connection framework (see gauche.connection - Connection framework), the following methods can be called on a tls object. Notably, the first two can be used to obtain IP address of the underlying connection.

connection-self-address (c <tls)
connection-peer-address (c <tls>)
connection-input-port (c <tls>)
connection-output-port (c <tls>)
connection-close (c <tls>)


For Development HEAD DRAFTSearch (procedure/syntax/module):
DRAFT