1/* Part of SWI-Prolog 2 3 Author: Jan van der Steen, Matt Lilley and Jan Wielemaker, 4 E-mail: J.Wielemaker@vu.nl 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 2004-2017, SWI-Prolog Foundation 7 VU University Amsterdam 8 All rights reserved. 9 10 Redistribution and use in source and binary forms, with or without 11 modification, are permitted provided that the following conditions 12 are met: 13 14 1. Redistributions of source code must retain the above copyright 15 notice, this list of conditions and the following disclaimer. 16 17 2. Redistributions in binary form must reproduce the above copyright 18 notice, this list of conditions and the following disclaimer in 19 the documentation and/or other materials provided with the 20 distribution. 21 22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 POSSIBILITY OF SUCH DAMAGE. 34*/ 35 36:- module(ssl, 37 [ load_certificate/2, % +Stream, -Certificate 38 load_private_key/3, % +Stream, +Password, -Key 39 load_public_key/2, % +Stream, -Key 40 load_crl/2, % +Stream, -Crl 41 system_root_certificates/1, % -List 42 cert_accept_any/5, % +SSL, +ProblemCertificate, 43 % +AllCertificates, +FirstCertificate, 44 % +Error 45 ssl_context/3, % +Role, -Config, :Options 46 ssl_add_certificate_key/4, % +Config, +Cert, +Key, -Config 47 ssl_set_options/3, % +Config0, -Config, +Options 48 ssl_negotiate/5, % +Config, +PlainRead, +PlainWrite, 49 % -SSLRead, -SSLWrite 50 ssl_peer_certificate/2, % +Stream, -Certificate 51 ssl_peer_certificate_chain/2, % +Stream, -Certificates 52 ssl_session/2, % +Stream, -Session 53 ssl_secure_ciphers/1 % -Ciphers 54 ]). 55:- use_module(library(option)). 56:- use_module(library(settings)). 57:- use_module(library(crypto), []). % force initialization of libcrypto 58 59:- use_foreign_library(foreign(ssl4pl)). 60 61:- meta_predicate 62 ssl_context( , , ), 63 ssl_set_options( , , ). 64 65:- predicate_options(ssl_context/3, 3, 66 [ host(atom), 67 port(integer), 68 certificate_file(atom), 69 key_file(atom), 70 certificate_key_pairs(any), 71 password(any), 72 cipher_list(any), 73 ecdh_curve(any), 74 pem_password_hook(callable), 75 cacert_file(any), 76 crl(any), 77 require_crl(boolean), 78 cert_verify_hook(callable), 79 peer_cert(boolean), 80 close_parent(boolean), 81 close_notify(boolean), 82 sni_hook(callable) 83 ]).
110:- setting(secure_ciphers, atom,
111 'EECDH+AESGCM:EDH+AESGCM:EECDH+AES256:EDH+AES256:EECDH+CHACHA20:EDH+CHACHA20',
112 "Default set of ciphers considered secure").
client
. Otherwise,
certificate verification may fail when negotiating a
secure connection.key_file(+FileName)
option. A server must have at
least one certificate before clients can connect. A client
must have a certificate only if the server demands the client
to identify itself with a client certificate using the
peer_cert(true)
option. If a certificate is provided, it is
necessary to also provide a matching private key via the
key_file/1 option. To configure multiple certificates, use the
option certificate_key_pairs/1 instead. Alternatively, use
ssl_add_certificate_key/4 to add certificates and keys to an
existing context.password(+Text)
or
pem_password_hook(:Goal)
option.call(Goal, +SSL, -Password)
and typically unifies
Password with a string containing the password.require_crl(true)
and
provide neither of these options, verification will necessarily
failrequire_crl(true)
if you want CRLs to actually be checked by OpenSSL.system(root_certificates)
uses a list of
trusted root certificates as provided by the OS. See
system_root_certificates/1 for details.
Additional verification of the peer certificate as well as accepting certificates that are not trusted by the given set can be realised using the hook cert_verify_hook(:Goal).
call(Goal, +SSL, +ProblemCertificate, +AllCertificates, +FirstCertificate, +Error)
In case the certificate was verified by one of the provided
certifications from the cacert_file
option, Error is unified
with the atom verified
. Otherwise it contains the error
string passed from OpenSSL. Access will be granted iff the
predicate succeeds. See load_certificate/2 for a description
of the certificate terms. See cert_accept_any/5 for a dummy
implementation that accepts any certificate.
prime256v1
is used by default.true
, close the raw streams if the SSL streams are closed.
Default is false
.true
(default is false
), the server sends TLS
close_notify
when closing the connection. In addition,
this mitigates truncation attacks for both client and
server role: If EOF is encountered without having received a
TLS shutdown, an exception is raised. Well-designed
protocols are self-terminating, and this attack is therefore
very rarely a concern.sslv3
, tlsv1
, tlsv1_1
and tlsv1_2
.
This option is available with OpenSSL 1.1.0 and later, and
should be used instead of disable_ssl_methods/1
.sslv3
, tlsv1
, tlsv1_1
and tlsv1_2
.
This option is available with OpenSSL 1.1.0 and later, and
should be used instead of disable_ssl_methods/1
.sslv2
, sslv3
, sslv23
,
tlsv1
, tlsv1_1
and tlsv1_2
. This option is deprecated
starting with OpenSSL 1.1.0. Use min_protocol_version/1 and
max_protocol_version/1 instead.disable_ssl_methods
above.
Using this option is discouraged. When using OpenSSL 1.1.0
or later, this option is ignored, and a version-flexible method
is used to negotiate the connection. Using version-specific
methods is deprecated in recent OpenSSL versions, and this
option will become obsolete and ignored in the future.call(Goal, +SSL0, +HostName, -SSL)
Given the current context SSL0, and the host name of the client request, the predicate computes SSL which is used as the context for negotiating the connection. The first solution is used. If the predicate fails, the default options are used, which are those of the encompassing ssl_context/3 call. In that case, if no default certificate and key are specified, the client connection is rejected.
283ssl_context(Role, SSL, Module:Options) :-
284 select_option(ssl_method(Method), Options, O1, sslv23),
285 '_ssl_context'(Role, SSL, Module:O1, Method).
This predicate allows dual-stack RSA and ECDSA servers (for
example), and is an alternative for using the
certificate_key_pairs/1
option. As of OpenSSL 1.0.2, multiple
certificate types with completely independent certificate chains
are supported. If a certificate of the same type is added
repeatedly to a context, the result is undefined. Currently, up to
12 additional certificates of different types are admissible.
302ssl_add_certificate_key(SSL0, Cert, Key, SSL) :- 303 ssl_copy_context(SSL0, SSL), 304 '_ssl_add_certificate_key'(SSL, Cert, Key). 305 306ssl_copy_context(SSL0, SSL) :- 307 ssl_context(server, SSL, []), 308 '_ssl_init_from_context'(SSL0, SSL).
322ssl_set_options(SSL0, SSL, Options) :-
323 ssl_copy_context(SSL0, SSL),
324 '_ssl_set_options'(SSL, Options).
After a successful handshake and finishing the communication the
user must close SSLRead and SSLWrite, for example using
call_cleanup(close(SSLWrite), close(SSLRead))
. If the SSL
context (created with ssl_context/3 has the option
close_parent(true)
(default false
), closing SSLRead and
SSLWrite also closes the original PlainRead and PlainWrite
streams. Otherwise these must be closed explicitly by the user.
http_open(HTTPS_url, In, []), ssl_peer_certificate(In, Cert), memberchk(subject(Subject), Cert), memberchk('CN' = CommonName), Subject)
Note that the OpenSSL CA.pl
utility creates certificates that
have a human readable textual representation in front of the PEM
representation. You can use the following to skip to the
certificate if you know it is a PEM certificate:
skip_to_pem_cert(In) :- repeat, ( peek_char(In, '-') -> ! ; skip(In, 0'\n), at_end_of_stream(In), ! ).
revoked(+Serial, DateOfRevocation)
system(root_certificates)
. The list is obtained using an OS
specific process. The current implementation is as follows:
"ROOT"
certificates from the OS.system_cacert_filename
. The initial
value of this flag is operating system dependent. For
security reasons, the flag can only be set prior to using
the SSL library. For example:
:- use_module(library(ssl)). :- set_prolog_flag(system_cacert_filename, '/home/jan/ssl/ca-bundle.crt').
private_key(KeyTerm)
where KeyTerm is an rsa/8 term
representing an RSA key, or ec/3 for EC keys.public_key(KeyTerm)
where KeyTerm is an rsa/8 term
representing an RSA key, or ec/3 for EC keys.http_open('https:/...', In, [ cert_verify_hook(cert_accept_any) ])
493cert_accept_any(_SSL,
494 _ProblemCertificate, _AllCertificates, _FirstCertificate,
495 _Error).
Note that obsolete ciphers must be disabled to reliably prevent protocol downgrade attacks.
The Ciphers list is read from the setting ssl:secure_ciphers
and
can be controlled using set_setting/2 and other predicates from
library(settings)
.
BEWARE: This list must be changed when attacks on these ciphers become known! Keep an eye on this setting and adapt it as necessary in the future.
516ssl_secure_ciphers(Cs) :- 517 setting(secure_ciphers, Cs). 518 519 520 /******************************* 521 * MESSAGES * 522 *******************************/ 523 524:- multifile 525 prolog:error_message//1. 526 527prologerror_message(ssl_error(ID, _Library, Function, Reason)) --> 528 [ 'SSL(~w) ~w: ~w'-[ID, Function, Reason] ]
Secure Socket Layer (SSL) library
An SSL server and client can be built with the (abstracted) predicate calls from the table below. The
tcp_
predicates are provided bylibrary(socket)
. The predicate ssl_context/3 defines properties of the SSL connection, while ssl_negotiate/5 establishes the SSL connection based on the wire streams created by the TCP predicates and the context.The library is abstracted to communication over streams, and is not reliant on those streams being directly attached to sockets. The
tcp_
calls here are simply the most common way to use the library. Other two-way communication channels such as (named), pipes can just as easily be used.library(socket)
,library(http/http_open)
,library(crypto)
*/