From: Javier Sagredo Date: Tue, 16 Jun 2026 22:38:06 +0000 (+0200) Subject: Merge branch 'js/rustls' into js/integration X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=198dd5b7448f69ac689adffed1bc79567cb7912b;p=scryer-prolog.git Merge branch 'js/rustls' into js/integration --- 198dd5b7448f69ac689adffed1bc79567cb7912b diff --cc src/lib/tls.pl index c317857c,f974accd..9e15d301 --- a/src/lib/tls.pl +++ b/src/lib/tls.pl @@@ -49,66 -47,62 +50,73 @@@ tls_client_context(tls_context(Host), O tls_client_negotiate(tls_context(Host), S0, S) :- '$tls_client_connect'(Host, S0, S). -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TLS Servers - =========== - - Use tls_server_context/2 to create a TLS context, for example with: - - tls_server_context(Context, [certificate(Cert),key(Key)]) - - where Cert is a list of characters with the contents of a - PEM-encoded certificate chain, and Key is a list of characters with - the contents of the corresponding PEM-encoded private key. The - private key may be in PKCS #8, PKCS #1 (RSA) or SEC1 (EC) format. - - The certificate chain should contain a leaf certificate followed by - any intermediate certificates that should be sent to clients to - allow them to build a chain to a trusted root. The chain - certificates should be in order from the leaf certificate towards - the root. - - You can use phrase_from_file/3 from library(pio) and seq//1 from - library(dcgs) to read the contents of "cert.pem" and "key.pem" into - strings: - - phrase_from_file(seq(Cert), "cert.pem"), phrase_from_file(seq(Key), "key.pem") - - The obtained context should be treated as an opaque Prolog term. - - Using the context and an existing stream S0 (for example, the - result of socket_server_accept/4), a TLS stream S can be negotiated - by a Prolog-based server with: - - tls_server_negotiate(Context, S0, S) - - S will be an encrypted and authenticated stream with the client. - - The advantage of separating the creation of the server context from - negotiating a connection is that the context can be created only - once, and quickly cloned for every incoming connection. This is - currently not implemented: In the present implementation, a new context - is created for every connection, using the specified parameters. -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - +%% tls_server_context(-Context, +Options) +% +% Use `tls_server_context/2` to create a TLS context, for example with: +% +% ``` - % tls_server_context(Context, [pkcs12(Chars)]) ++% tls_server_context(Context, [certificate(Cert),key(Key)]) +% ``` +% - % where Chars is a list of characters with the contents of a DER-formatted PKCS - % #12 archive. The option `password(Ps)` can be used to specify the password - % `Ps` (also a string) for decrypting the key. On some versions of OSX, and - % potentially also on other platforms, empty passwords are not supported. ++% where `Cert` is a list of characters with the contents of a PEM-encoded ++% certificate chain, and `Key` is a list of characters with the contents of the ++% corresponding PEM-encoded private key. The private key may be in PKCS #8, PKCS ++% #1 (RSA) or SEC1 (EC) format. +% - % The archive should contain a leaf certificate and its private key, as well any - % intermediate certificates that should be sent to clients to allow them to - % build a chain to a trusted root. The chain certificates should be in order - % from the leaf certificate towards the root. ++% The certificate chain should contain a leaf certificate followed by any ++% intermediate certificates that should be sent to clients to allow them to build ++% a chain to a trusted root. The chain certificates should be in order from the ++% leaf certificate towards the root. +% - % PKCS #12 archives typically have the file extension `.p12` or `.pfx`, and can - % be created with the OpenSSL `pkcs12` tool: ++% You can use `phrase_from_file/3` from `library(pio)` and `seq//1` from `library(dcgs)` ++% to read the contents of "cert.pem" and "key.pem" into strings: +% +% ``` - % $ openssl pkcs12 -export -out identity.pfx \ - % -inkey key.pem -in cert.pem -certfile chain_certs.pem - % ``` - % - % You can use `phrase_from_file/3` from `library(pio)` and `seq//1` from - % `library(dcgs)` to read the contents of `identity.pfx` into a string: - % - % ``` - % phrase_from_file(seq(Chars), "identity.pfx", [type(binary)]) ++% phrase_from_file(seq(Cert), "cert.pem"), phrase_from_file(seq(Key), "key.pem") +% ``` +% +% The obtained context should be treated as an opaque Prolog term. - tls_server_context(tls_context(Cert,Password), Options) :- - ( member(pcks12(Cert), Options) -> + tls_server_context(tls_context(Cert,Key), Options) :- + ( member(certificate(Cert), Options) -> must_be(chars, Cert) - ; domain_error(contains_pcks12, Options, tls_server_context/2) + ; domain_error(contains_certificate, Options, tls_server_context/2) ), - ( member(password(Password), Options) -> - must_be(chars, Password) - ; Password = "" + ( member(key(Key), Options) -> + must_be(chars, Key) + ; domain_error(contains_key, Options, tls_server_context/2) ). - %% tls_server_negotiate(+Context, +Stream0, -Stream) ++%% tls_server_negotiate(+Context, +Stream0, -Stream, +Options) +% +% Using the context and an existing stream `S0` (for example, the result of +% `socket_server_accept/4`), a TLS stream `S` can be negotiated by a +% Prolog-based server with: +% +% ``` - % tls_server_negotiate(Context, S0, S) ++% tls_server_negotiate(Context, S0, S, Options) +% ``` +% +% `S` will be an encrypted and authenticated stream with the client. +% ++% Currently, the only existing option is `client_certificate(Cert)` where `Cert` ++% will be unified with the client certificate if the client provides one, or the ++% atom `none` if none is provided. To get the client certificate, use `Options = ++% [client_certificate(Cert)]`. ++% +% The advantage of separating the creation of the server context from +% negotiating a connection is that the context can be created only once, and +% quickly cloned for every incoming connection. This is currently not +% implemented: In the present implementation, a new context is created for every +% connection, using the specified parameters. - tls_server_negotiate(tls_context(Cert,Password), S0, S) :- - '$tls_accept_client'(Cert, Password, S0, S). ++tls_server_negotiate(tls_context(Cert,Key), S0, S, Options) :- ++ must_be(list, Options), ++ ( member(client_certificate(ClientCert), Options) -> ++ '$tls_accept_client'(Cert, Key, S0, S, ClientCert) ++ ; '$tls_accept_client'(Cert, Key, S0, S, _) ++ ). ++ ++%% tls_server_negotiate(+Context, +Stream0, -Stream) ++% ++% Like `tls_server_negotiate/4` with empty options. + tls_server_negotiate(Ctx, S0, S) :- + tls_server_negotiate(Ctx, S0, S, []). - -tls_server_negotiate(tls_context(Cert,Key), S0, S, Options) :- - member(client_certificate(ClientCert), Options) -> - '$tls_accept_client'(Cert, Key, S0, S, ClientCert) - ; '$tls_accept_client'(Cert, Key, S0, S, _).